1 | // Copyright 2014 The Flutter Authors. All rights reserved. |
2 | // Use of this source code is governed by a BSD-style license that can be |
3 | // found in the LICENSE file. |
4 | |
5 | import 'package:flutter/gestures.dart'; |
6 | import 'package:flutter/material.dart'; |
7 | |
8 | /// Flutter code sample for [GestureDetector]. |
9 | |
10 | void main() { |
11 | debugPrintGestureArenaDiagnostics = true; |
12 | runApp(const NestedGestureDetectorsApp()); |
13 | } |
14 | |
15 | enum _OnTapWinner { none, yellow, green } |
16 | |
17 | class NestedGestureDetectorsApp extends StatelessWidget { |
18 | const NestedGestureDetectorsApp({super.key}); |
19 | |
20 | @override |
21 | Widget build(BuildContext context) { |
22 | return MaterialApp( |
23 | home: Scaffold( |
24 | appBar: AppBar(title: const Text('Nested GestureDetectors' )), |
25 | body: const NestedGestureDetectorsExample(), |
26 | ), |
27 | ); |
28 | } |
29 | } |
30 | |
31 | class NestedGestureDetectorsExample extends StatefulWidget { |
32 | const NestedGestureDetectorsExample({super.key}); |
33 | |
34 | @override |
35 | State<NestedGestureDetectorsExample> createState() => _NestedGestureDetectorsExampleState(); |
36 | } |
37 | |
38 | class _NestedGestureDetectorsExampleState extends State<NestedGestureDetectorsExample> { |
39 | bool _isYellowTranslucent = false; |
40 | _OnTapWinner _winner = _OnTapWinner.none; |
41 | final Border highlightBorder = Border.all(color: Colors.red, width: 5); |
42 | |
43 | @override |
44 | Widget build(BuildContext context) { |
45 | return Column( |
46 | children: <Widget>[ |
47 | Expanded( |
48 | child: GestureDetector( |
49 | onTap: () { |
50 | debugPrint('Green onTap' ); |
51 | setState(() { |
52 | _winner = _OnTapWinner.green; |
53 | }); |
54 | }, |
55 | onTapDown: (_) => debugPrint('Green onTapDown' ), |
56 | onTapCancel: () => debugPrint('Green onTapCancel' ), |
57 | child: Container( |
58 | alignment: Alignment.center, |
59 | decoration: BoxDecoration( |
60 | border: _winner == _OnTapWinner.green ? highlightBorder : null, |
61 | color: Colors.green, |
62 | ), |
63 | child: GestureDetector( |
64 | // Setting behavior to transparent or opaque as no impact on |
65 | // parent-child hit testing. A tap on 'Yellow' is also in |
66 | // 'Green' bounds. Both enter the gesture arena, 'Yellow' wins |
67 | // because it is in front. |
68 | behavior: |
69 | _isYellowTranslucent ? HitTestBehavior.translucent : HitTestBehavior.opaque, |
70 | onTap: () { |
71 | debugPrint('Yellow onTap' ); |
72 | setState(() { |
73 | _winner = _OnTapWinner.yellow; |
74 | }); |
75 | }, |
76 | child: Container( |
77 | alignment: Alignment.center, |
78 | decoration: BoxDecoration( |
79 | border: _winner == _OnTapWinner.yellow ? highlightBorder : null, |
80 | color: Colors.amber, |
81 | ), |
82 | width: 200, |
83 | height: 200, |
84 | child: Text( |
85 | 'HitTextBehavior. ${_isYellowTranslucent ? 'translucent' : 'opaque' }' , |
86 | textAlign: TextAlign.center, |
87 | ), |
88 | ), |
89 | ), |
90 | ), |
91 | ), |
92 | ), |
93 | Padding( |
94 | padding: const EdgeInsets.all(8.0), |
95 | child: Row( |
96 | children: <Widget>[ |
97 | ElevatedButton( |
98 | child: const Text('Reset' ), |
99 | onPressed: () { |
100 | setState(() { |
101 | _isYellowTranslucent = false; |
102 | _winner = _OnTapWinner.none; |
103 | }); |
104 | }, |
105 | ), |
106 | const SizedBox(width: 8), |
107 | ElevatedButton( |
108 | child: Text( |
109 | 'Set Yellow behavior to ${_isYellowTranslucent ? 'opaque' : 'translucent' }' , |
110 | ), |
111 | onPressed: () { |
112 | setState(() => _isYellowTranslucent = !_isYellowTranslucent); |
113 | }, |
114 | ), |
115 | ], |
116 | ), |
117 | ), |
118 | ], |
119 | ); |
120 | } |
121 | |
122 | @override |
123 | void dispose() { |
124 | debugPrintGestureArenaDiagnostics = false; |
125 | super.dispose(); |
126 | } |
127 | } |
128 | |