Skip to content

Commit 0af426f

Browse files
Animate a CupertinoButton based on tap move events only if the move happens between a tap down and a tap up (#165729)
Fixes flutter/flutter#165724
1 parent cc845eb commit 0af426f

File tree

2 files changed

+31
-3
lines changed

2 files changed

+31
-3
lines changed

packages/flutter/lib/src/cupertino/button.dart

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -356,15 +356,18 @@ class _CupertinoButtonState extends State<CupertinoButton> with SingleTickerProv
356356
}
357357

358358
bool _buttonHeldDown = false;
359+
bool _tapInProgress = false;
359360

360361
void _handleTapDown(TapDownDetails event) {
362+
_tapInProgress = true;
361363
if (!_buttonHeldDown) {
362364
_buttonHeldDown = true;
363365
_animate();
364366
}
365367
}
366368

367369
void _handleTapUp(TapUpDetails event) {
370+
_tapInProgress = false;
368371
if (_buttonHeldDown) {
369372
_buttonHeldDown = false;
370373
_animate();
@@ -377,19 +380,20 @@ class _CupertinoButtonState extends State<CupertinoButton> with SingleTickerProv
377380
}
378381

379382
void _handleTapCancel() {
383+
_tapInProgress = false;
380384
if (_buttonHeldDown) {
381385
_buttonHeldDown = false;
382386
_animate();
383387
}
384388
}
385389

386-
void _handTapMove(TapMoveDetails event) {
390+
void _handleTapMove(TapMoveDetails event) {
387391
final RenderBox renderObject = context.findRenderObject()! as RenderBox;
388392
final Offset localPosition = renderObject.globalToLocal(event.globalPosition);
389393
final bool buttonShouldHeldDown = renderObject.paintBounds
390394
.inflate(CupertinoButton.tapMoveSlop())
391395
.contains(localPosition);
392-
if (buttonShouldHeldDown != _buttonHeldDown) {
396+
if (_tapInProgress && buttonShouldHeldDown != _buttonHeldDown) {
393397
_buttonHeldDown = buttonShouldHeldDown;
394398
_animate();
395399
}
@@ -512,7 +516,7 @@ class _CupertinoButtonState extends State<CupertinoButton> with SingleTickerProv
512516
instance.onTapDown = enabled ? _handleTapDown : null;
513517
instance.onTapUp = enabled ? _handleTapUp : null;
514518
instance.onTapCancel = enabled ? _handleTapCancel : null;
515-
instance.onTapMove = enabled ? _handTapMove : null;
519+
instance.onTapMove = enabled ? _handleTapMove : null;
516520
instance.gestureSettings = gestureSettings;
517521
},
518522
),

packages/flutter/test/cupertino/button_test.dart

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -912,6 +912,30 @@ void main() {
912912
expect(opacity.opacity.value, 0.4);
913913
}, variant: TargetPlatformVariant.all());
914914

915+
testWidgets('Drag outside button within ListView does not leave the button pressed', (
916+
WidgetTester tester,
917+
) async {
918+
await tester.pumpWidget(
919+
boilerplate(
920+
child: ListView(
921+
children: <Widget>[CupertinoButton(onPressed: () {}, child: const Text('Tap me'))],
922+
),
923+
),
924+
);
925+
final FadeTransition opacity = tester.widget(
926+
find.descendant(of: find.byType(CupertinoButton), matching: find.byType(FadeTransition)),
927+
);
928+
929+
final TestGesture gesture = await tester.createGesture();
930+
addTearDown(gesture.removePointer);
931+
932+
await gesture.down(tester.getTopLeft(find.byType(CupertinoButton)));
933+
await gesture.moveBy(const Offset(1, 1));
934+
await gesture.moveBy(Offset(0, -CupertinoButton.tapMoveSlop() - 5));
935+
await tester.pumpAndSettle();
936+
expect(opacity.opacity.value, 1.0);
937+
});
938+
915939
testWidgets('onPressed trigger takes into account MoveSlop.', (WidgetTester tester) async {
916940
bool value = false;
917941
await tester.pumpWidget(

0 commit comments

Comments
 (0)