FlutterでSingleChildScrollView
とGestureDetector
を併用してジェスチャー(スワイプ)を感知したい!
概要
今回の記事では、FlutterでSingleChildScrollView
とGestureDetector
を併用してジェスチャー(スワイプ)を感知する手順を掲載する。
仕様書
環境
- Android Studio Giraffe | 2023.2.1 Patch 2
- Flutter 3.19.6
手順書
過去のFlutternのプロジェクトをいじってたんだけども、画面上部から下に向けたスワイプのジェスチャーが感知しなくなった。
コードは下記のような感じでGestureDetector
の中にSingleChildScrollView
が配置されてる感じ。
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
home: Scaffold(
body: const GestureAndScrollViewSample1()
)
)
);
}
class GestureAndScrollViewSample1 extends StatelessWidget {
const GestureAndScrollViewSample1({super.key});
@override
Widget build(BuildContext context) {
return SafeArea(
child: GestureDetector(
onVerticalDragEnd: (DragEndDetails details) {
if (details.primaryVelocity! > 0.0) {
debugPrint('Swiped Down!!!');
} else if (details.primaryVelocity! < 0.0) {
debugPrint('Swiped Up!!!');
}
},
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: [
Container(
color: Colors.amber,
height: 500,
child: const Center(
child: Text('Amber'),
),
),
Container(
color: Colors.red,
height: 500,
child: const Center(
child: Text('Red'),
),
),
Container(
color: Colors.green,
height: 500,
child: const Center(
child: Text('Green'),
),
),
Container(
color: Colors.blue,
height: 500,
child: const Center(
child: Text('Blue'),
),
),
Container(
color: Colors.purple,
height: 500,
child: const Center(
child: Text('Purple'),
),
),
]),
),
),
);
}
}
画面上部から下に向けたスワイプを感知するとSwiped Down!!!
と出力されるはずなんだけども、出力されない!以前は表示されたはずなのに!
いろいろ試してて、親子関係を逆にSingleChildScrollView
の中にGestureDetector
を配置したらジェスチャーを感知するようになった。
import 'package:flutter/material.dart';
class GestureAndScrollViewSample2 extends StatelessWidget {
const GestureAndScrollViewSample2({super.key});
@override
Widget build(BuildContext context) {
return SafeArea(
child: SingleChildScrollView(
child: GestureDetector(
onVerticalDragEnd: (DragEndDetails details) {
if (details.primaryVelocity! > 0.0) {
debugPrint('Swiped Down!!!');
} else if (details.primaryVelocity! < 0.0) {
debugPrint('Swiped Up!!!');
}
},
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: [
Container(
color: Colors.amber,
height: 500,
child: const Center(
child: Text('Amber'),
),
),
Container(
color: Colors.red,
height: 500,
child: const Center(
child: Text('Red'),
),
),
Container(
color: Colors.green,
height: 500,
child: const Center(
child: Text('Green'),
),
),
Container(
color: Colors.blue,
height: 500,
child: const Center(
child: Text('Blue'),
),
),
Container(
color: Colors.purple,
height: 500,
child: const Center(
child: Text('Purple'),
),
),
]),
),
),
);
}
}
バージョンアップで使用が変わったのか、自分の勘違いなのか。
もうちょっといじってて分かったのが、SingleChildScrollView
がスクロール不要な状態(子が小さいとか)だとGestureDetector
が親だろうが子だろうがジェクチャーを感知できる。
class GestureAndScrollViewSample2 extends StatelessWidget {
const GestureAndScrollViewSample2({super.key});
@override
Widget build(BuildContext context) {
return SafeArea(
child: GestureDetector(
onVerticalDragEnd: (DragEndDetails details) {
if (details.primaryVelocity! > 0.0) {
debugPrint('Swiped Down!!!');
} else if (details.primaryVelocity! < 0.0) {
debugPrint('Swiped Up!!!');
}
},
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: [
Container(
color: Colors.amber,
child: const Center(
child: Text('Amber'),
),
),
Container(
color: Colors.red,
child: const Center(
child: Text('Red'),
),
),
Container(
color: Colors.green,
child: const Center(
child: Text('Green'),
),
),
Container(
color: Colors.blue,
child: const Center(
child: Text('Blue'),
),
),
Container(
color: Colors.purple,
child: const Center(
child: Text('Purple'),
),
),
]),
),
),
);
}
}
うーん。
まとめ(感想文)
ケースにもよるんだけども、自分の場合は単純にスワイプしたら画面を更新したかっただけないのでGestureDetector
じゃなくてRefreshIndicator
の方が合ってたということに後日気づくのであった。