forked from flutter/plugins
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add an example and update
GestureDetector
documentation (#102360)
- Loading branch information
Showing
3 changed files
with
271 additions
and
0 deletions.
There are no files selected for viewing
127 changes: 127 additions & 0 deletions
127
examples/api/lib/widgets/gesture_detector/gesture_detector.2.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
// Copyright 2014 The Flutter Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
import 'package:flutter/gestures.dart'; | ||
import 'package:flutter/material.dart'; | ||
|
||
void main() { | ||
debugPrintGestureArenaDiagnostics = true; | ||
runApp(const NestedGestureDetectorsApp()); | ||
} | ||
|
||
enum _OnTapWinner { none, yellow, green } | ||
|
||
class NestedGestureDetectorsApp extends StatelessWidget { | ||
const NestedGestureDetectorsApp({super.key}); | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
return MaterialApp( | ||
home: Scaffold( | ||
appBar: AppBar(title: const Text('Nested GestureDetectors')), | ||
body: const NestedGestureDetectorsExample(), | ||
), | ||
); | ||
} | ||
} | ||
|
||
class NestedGestureDetectorsExample extends StatefulWidget { | ||
const NestedGestureDetectorsExample({super.key}); | ||
|
||
@override | ||
State<NestedGestureDetectorsExample> createState() => _NestedGestureDetectorsExampleState(); | ||
} | ||
|
||
class _NestedGestureDetectorsExampleState | ||
extends State<NestedGestureDetectorsExample> { | ||
bool _isYellowTranslucent = false; | ||
_OnTapWinner _winner = _OnTapWinner.none; | ||
final Border highlightBorder = Border.all(color: Colors.red, width: 5); | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
return Column( | ||
children: <Widget>[ | ||
Expanded( | ||
child: GestureDetector( | ||
onTap: () { | ||
debugPrint('Green onTap'); | ||
setState(() { | ||
_winner = _OnTapWinner.green; | ||
}); | ||
}, | ||
onTapDown: (_) => debugPrint('Green onTapDown'), | ||
onTapCancel: () => debugPrint('Green onTapCancel'), | ||
child: Container( | ||
alignment: Alignment.center, | ||
decoration: BoxDecoration( | ||
border: _winner == _OnTapWinner.green ? highlightBorder : null, | ||
color: Colors.green, | ||
), | ||
child: GestureDetector( | ||
// Setting behavior to transparent or opaque as no impact on | ||
// parent-child hit testing. A tap on 'Yellow' is also in | ||
// 'Green' bounds. Both enter the gesture arena, 'Yellow' wins | ||
// because it is in front. | ||
behavior: _isYellowTranslucent | ||
? HitTestBehavior.translucent | ||
: HitTestBehavior.opaque, | ||
onTap: () { | ||
debugPrint('Yellow onTap'); | ||
setState(() { | ||
_winner = _OnTapWinner.yellow; | ||
}); | ||
}, | ||
child: Container( | ||
alignment: Alignment.center, | ||
decoration: BoxDecoration( | ||
border: _winner == _OnTapWinner.yellow ? highlightBorder : null, | ||
color: Colors.amber, | ||
), | ||
width: 200, | ||
height: 200, | ||
child: Text( | ||
'HitTextBehavior.${_isYellowTranslucent ? 'translucent' : 'opaque'}', | ||
textAlign: TextAlign.center, | ||
), | ||
), | ||
), | ||
), | ||
), | ||
), | ||
Padding( | ||
padding: const EdgeInsets.all(8.0), | ||
child: Row( | ||
children: <Widget>[ | ||
ElevatedButton( | ||
child: const Text('Reset'), | ||
onPressed: () { | ||
setState(() { | ||
_isYellowTranslucent = false; | ||
_winner = _OnTapWinner.none; | ||
}); | ||
}, | ||
), | ||
const SizedBox(width: 8), | ||
ElevatedButton( | ||
child: Text( | ||
'Set Yellow behavior to ${_isYellowTranslucent ? 'opaque' : 'translucent'}', | ||
), | ||
onPressed: () { | ||
setState(() => _isYellowTranslucent = !_isYellowTranslucent); | ||
}, | ||
), | ||
], | ||
), | ||
), | ||
], | ||
); | ||
} | ||
|
||
@override | ||
void dispose() { | ||
debugPrintGestureArenaDiagnostics = false; | ||
super.dispose(); | ||
} | ||
} |
94 changes: 94 additions & 0 deletions
94
examples/api/test/widgets/gesture_detector/gesture_detector.2_test.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
// Copyright 2014 The Flutter Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
import 'package:flutter/material.dart'; | ||
import 'package:flutter_api_samples/widgets/gesture_detector/gesture_detector.2.dart' | ||
as example; | ||
import 'package:flutter_test/flutter_test.dart'; | ||
|
||
void main() { | ||
|
||
void expectBorders( | ||
WidgetTester tester, { | ||
required bool expectGreenHasBorder, | ||
required bool expectYellowHasBorder, | ||
}) { | ||
final Finder containerFinder = find.byType(Container); | ||
final Finder greenFinder = containerFinder.first; | ||
final Finder yellowFinder = containerFinder.last; | ||
|
||
final Container greenContainer = tester.firstWidget<Container>(greenFinder); | ||
final BoxDecoration? greenDecoration = greenContainer.decoration as BoxDecoration?; | ||
expect(greenDecoration?.border, expectGreenHasBorder ? isNot(null) : null); | ||
|
||
final Container yellowContainer = tester.firstWidget<Container>(yellowFinder); | ||
final BoxDecoration? yellowDecoration = yellowContainer.decoration as BoxDecoration?; | ||
expect(yellowDecoration?.border, expectYellowHasBorder ? isNot(null) : null); | ||
} | ||
|
||
void expectInnerGestureDetectorBehavior(WidgetTester tester, HitTestBehavior behavior) { | ||
// Note that there is a third GestureDetector added by Scaffold | ||
final Finder innerGestureDetectorFinder = find.byType(GestureDetector).at(1); | ||
final GestureDetector innerGestureDetector = tester.firstWidget<GestureDetector>(innerGestureDetectorFinder); | ||
expect(innerGestureDetector.behavior, behavior); | ||
} | ||
|
||
testWidgets('Only the green Container shows a red border when tapped', (WidgetTester tester) async { | ||
await tester.pumpWidget( | ||
const example.NestedGestureDetectorsApp(), | ||
); | ||
|
||
final Finder greenFinder = find.byType(Container).first; | ||
final Offset greenTopLeftCorner = tester.getTopLeft(greenFinder); | ||
await tester.tapAt(greenTopLeftCorner); | ||
await tester.pumpAndSettle(); | ||
expectBorders(tester, expectGreenHasBorder: true, expectYellowHasBorder: false); | ||
|
||
// Tap on the button to toggle inner GestureDetector.behavior | ||
final Finder toggleBehaviorFinder = find.byType(ElevatedButton).last; | ||
await tester.tap(toggleBehaviorFinder); | ||
await tester.pump(); | ||
expectInnerGestureDetectorBehavior(tester, HitTestBehavior.translucent); | ||
|
||
// Tap again on the green container, expect nothing changed | ||
await tester.tapAt(greenTopLeftCorner); | ||
await tester.pump(); | ||
expectBorders(tester, expectGreenHasBorder: true, expectYellowHasBorder: false); | ||
|
||
// Tap on the reset button | ||
final Finder resetFinder = find.byType(ElevatedButton).first; | ||
await tester.tap(resetFinder); | ||
await tester.pump(); | ||
expectInnerGestureDetectorBehavior(tester, HitTestBehavior.opaque); | ||
}); | ||
|
||
testWidgets('Only the yellow Container shows a red border when tapped', (WidgetTester tester) async { | ||
await tester.pumpWidget( | ||
const example.NestedGestureDetectorsApp(), | ||
); | ||
|
||
final Finder yellowFinder = find.byType(Container).last; | ||
final Offset yellowTopLeftCorner = tester.getTopLeft(yellowFinder); | ||
await tester.tapAt(yellowTopLeftCorner); | ||
await tester.pump(); | ||
expectBorders(tester, expectGreenHasBorder: false, expectYellowHasBorder: true); | ||
|
||
// Tap on the button to toggle inner GestureDetector.behavior | ||
final Finder toggleBehaviorFinder = find.byType(ElevatedButton).last; | ||
await tester.tap(toggleBehaviorFinder); | ||
await tester.pump(); | ||
expectInnerGestureDetectorBehavior(tester, HitTestBehavior.translucent); | ||
|
||
// Tap again on the yellow container, expect nothing changed | ||
await tester.tapAt(yellowTopLeftCorner); | ||
await tester.pump(); | ||
expectBorders(tester, expectGreenHasBorder: false, expectYellowHasBorder: true); | ||
|
||
// Tap on the reset button | ||
final Finder resetFinder = find.byType(ElevatedButton).first; | ||
await tester.tap(resetFinder); | ||
await tester.pump(); | ||
expectInnerGestureDetectorBehavior(tester, HitTestBehavior.opaque); | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters