質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Flutter

Flutterは、iOSとAndroidのアプリを同じコードで開発するためのフレームワークです。オープンソースで開発言語はDart。双方のプラットフォームにおける高度な実行パフォーマンスと開発効率を提供することを目的としています。

Dart

Dartは、Googleによって開発されたJavaScriptの代替となることを目的に作られた、ウェブ向けのプログラミング言語である。

Q&A

解決済

2回答

742閲覧

flutterのGestureDetectorが入れ子構造になっている時のイベント処理を管理したい

nekogrammer

総合スコア33

Flutter

Flutterは、iOSとAndroidのアプリを同じコードで開発するためのフレームワークです。オープンソースで開発言語はDart。双方のプラットフォームにおける高度な実行パフォーマンスと開発効率を提供することを目的としています。

Dart

Dartは、Googleによって開発されたJavaScriptの代替となることを目的に作られた、ウェブ向けのプログラミング言語である。

0グッド

0クリップ

投稿2023/05/24 10:48

実現したいこと

画面全体に対するGestureDetectorがあり、
さらにその画面内にGestureDetectorを備えたウィジェットが配置してあります。
親GestureDetectorウィジェットと子GestureDetectorウィジェットの関係で、
子ウィジェットの方をタップした時に、親の方のGestureDetectorが反応してしまいます。
これを子GestureDetectorだけが反応するようにしたいです。

発生している問題・エラーメッセージ

onTapDownやonLongPressなどのイベントメソッドが
入れ子構造になっているすべてのGestureDetectorにて検出されてしまう。
具体的には子のテキストをダブルタップしても、そのタップ判定が
親のGestureDetectorに吸われて親の処理が発動してしまう。
子に対するイベントは、子だけで止めたいです。

該当のソースコード

dart

1 2class _TaskBasicScreenState extends State<TaskBasicScreen> 3 with SingleTickerProviderStateMixin { 4 5 6 Widget build(BuildContext context) { 7 return Scaffold( 8 body: SafeArea( 9 /// 親のGestureDetector(画面全体) 10 child: GestureDetector( 11 behavior: HitTestBehavior.opaque, 12 onTapDown: (TapDownDetails details) { 13 // ダブルタップを検出ロジック 14 final now = Timestamp.now(); 15 final distance = 16 (_lastTapDownPosition - details.globalPosition).distance; 17 final timeDiff = now.millisecondsSinceEpoch - 18 _lastTapDownTime.millisecondsSinceEpoch; 19 if (distance < 50 && timeDiff < 400) { 20 /// ダブルタップ検出時はタスク追加画面に遷移する 21 pushToTaskAddScreen(); 22 } 23 // タップ情報を最新に更新する 24 _lastTapDownPosition = details.globalPosition; 25 _lastTapDownTime = now; 26 }, 27 28 /// 画面内のウィジェットカラム 29 child: Column( 30 children: [ 31 32 /// 子GestureDetector() 33 GestureDetector( 34 onLongPress: () { 35 pushToTitleEditScreen(); 36 }, 37 child: TitleField( 38 title: 'Title', 39 editMode: false, 40 ), 41 ), 42 43 /// タスクリスト 44 Expanded( 45 child: Consumer<GlobalInfo>( 46 builder: (context, taskTileList, child) { 47 // 以下略 48

試したこと

behavior: HitTestBehavior.opaque,
behavior: HitTestBehavior.translucent
behavior: HitTestBehavior.deferToChild,
など各種behaviorは試しましたが、期待通りの動作にはなりませんでした。

補足情報(FW/ツールのバージョンなど)

Android Studio
よろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

onTapDownを使うのであれば、それはしょうがないのでしょう。
onTapCancelを併用することでonTapDownが何かしらの理由で無効になったことを示すコールバックになるのでキャンセル処理を入れるとか。

ダブルタップを実現したいのであれば、用意されているonDoubleTapを呼び出したほうが簡単です。

onTapDownの件はGestureDetectorのAPI説明のTroubleshootingのところにさらっと書かれています。
読み解くのが難しいのですが、概要としてはこんな感じかな。onTapCancelも書かれているがそれは割愛します。

タップの処理はGestureRecognizerに一度送られて、そこで親子関係を見ながら適切なGestureDetectorの処理を1度だけ呼び出すようにする。
ただonTapDownは他の呼び出しに先駆けて呼び出される場合がある。

実際の動きは、以下の様なテストコードを作ってみるのが良いです。

dart

1 GestureDetector( 2 behavior: HitTestBehavior.opaque, 3 onTap: () => debugPrint("tap1"), 4 onTapUp: (_) => debugPrint("up tap1"), 5 onTapDown: (_) => debugPrint("down tap1"), 6 onTapCancel: () => debugPrint("cancel tap1"), 7 onDoubleTap: () => debugPrint("2 tap1"), 8 child: Column( 9 children: [ 10 GestureDetector( 11 onLongPress: () => debugPrint("long tap2"), 12 child: const Text("hoge1"), 13 ), 14 const Divider(height: 30), 15 GestureDetector( 16 onTap: () => debugPrint("tap3"), 17 child: const Text("hoge2"), 18 ), 19 ], 20 ), 21 ),

投稿2023/05/24 23:33

ta.fu

総合スコア1667

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ta.fuさん、回答ありがとうございます!
何が間違っているのかずっと分からなかったのですが、
onTapDownは他の呼び出しに先駆けて呼び出される場合がある、
という仕様のせいでイベントが筒抜けだったんですね。。。
出来ないことをずっとやろうとしていたことに気付けただけでも大変助かりました。

onDoubleTapの存在は知っていたのですが、
タップ座標をコールバック内で受け取れないので、
onTapDownを使ったダブルタップ検知で実装をしていました。

また、onTapDownとonDoubleTapを両方設定すると、
素早くダブルタップした時にonTapDownが発火しないなど、
色々と細かいところで問題があって、なかなかダブルタップの座標を取るのが難しいですね。。

回答を頂いてから色々と試してみましたが、
GestureDetectorだとどうやってもやりたいことの実現が難しそうなので、
RawGestureDetectorを使ってGestureDetectorのようなクラスを
自作するのがよさそうです。そっちの方向でトライしてみます。

ご回答、ありがとうございました。

投稿2023/05/25 03:24

nekogrammer

総合スコア33

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問