Improve TextField splash management: cancel() ... confirm() (#14130)
This commit is contained in:
parent
b94f757d77
commit
7b6af52c92
@ -190,7 +190,10 @@ class InkRipple extends InteractiveInkFeature {
|
|||||||
_radiusController
|
_radiusController
|
||||||
..duration = _kRadiusDuration
|
..duration = _kRadiusDuration
|
||||||
..forward();
|
..forward();
|
||||||
_fadeOutController.forward();
|
// This confirm may have been preceeded by a cancel.
|
||||||
|
_fadeInController.forward();
|
||||||
|
_fadeOutController
|
||||||
|
..animateTo(1.0, duration: _kFadeOutDuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -414,7 +414,6 @@ class _TextFieldState extends State<TextField> with AutomaticKeepAliveClientMixi
|
|||||||
|
|
||||||
void _cancelCurrentSplash() {
|
void _cancelCurrentSplash() {
|
||||||
_currentSplash?.cancel();
|
_currentSplash?.cancel();
|
||||||
_currentSplash = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
import 'package:flutter/gestures.dart' show kPressTimeout;
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:flutter/rendering.dart';
|
import 'package:flutter/rendering.dart';
|
||||||
@ -176,7 +177,13 @@ void main() {
|
|||||||
|
|
||||||
// Pointer is dragged below the textfield, splash is canceled.
|
// Pointer is dragged below the textfield, splash is canceled.
|
||||||
final TestGesture gesture1 = await tester.startGesture(tester.getCenter(find.text('label1')));
|
final TestGesture gesture1 = await tester.startGesture(tester.getCenter(find.text('label1')));
|
||||||
await tester.pumpAndSettle();
|
|
||||||
|
// Splashes start on tapDown.
|
||||||
|
// If the timeout is less than kPressTimout the recognizer will just trigger
|
||||||
|
// the onTapCancel callback. If the timeout is greater or equal to kPressTimout
|
||||||
|
// and less than kLongPressTimeout then onTapDown, onCancel will be called.
|
||||||
|
await tester.pump(kPressTimeout);
|
||||||
|
|
||||||
await gesture1.moveTo(const Offset(400.0, 300.0));
|
await gesture1.moveTo(const Offset(400.0, 300.0));
|
||||||
await gesture1.up();
|
await gesture1.up();
|
||||||
expect(confirmCount, 0);
|
expect(confirmCount, 0);
|
||||||
@ -184,11 +191,10 @@ void main() {
|
|||||||
|
|
||||||
// Pointer is dragged upwards causing a scroll, splash is canceled.
|
// Pointer is dragged upwards causing a scroll, splash is canceled.
|
||||||
final TestGesture gesture2 = await tester.startGesture(tester.getCenter(find.text('label2')));
|
final TestGesture gesture2 = await tester.startGesture(tester.getCenter(find.text('label2')));
|
||||||
await tester.pumpAndSettle();
|
await tester.pump(kPressTimeout);
|
||||||
await gesture2.moveBy(const Offset(0.0, -200.0), timeStamp: const Duration(milliseconds: 32));
|
await gesture2.moveBy(const Offset(0.0, -200.0));
|
||||||
await gesture2.up();
|
await gesture2.up();
|
||||||
expect(confirmCount, 0);
|
expect(confirmCount, 0);
|
||||||
expect(cancelCount, 2);
|
expect(cancelCount, 2);
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -251,4 +251,67 @@ void main() {
|
|||||||
expect(renderObj1, same(renderObj2));
|
expect(renderObj1, same(renderObj2));
|
||||||
expect(actualCallback1, same(actualCallback2)); // Should be cached.
|
expect(actualCallback1, same(actualCallback2)); // Should be cached.
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('Tap down occurs after kPressTimeout', (WidgetTester tester) async {
|
||||||
|
int tapDown = 0;
|
||||||
|
int tap = 0;
|
||||||
|
int tapCancel = 0;
|
||||||
|
int longPress = 0;
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
new Container(
|
||||||
|
alignment: Alignment.topLeft,
|
||||||
|
child: new Container(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
height: 100.0,
|
||||||
|
color: const Color(0xFF00FF00),
|
||||||
|
child: new GestureDetector(
|
||||||
|
onTapDown: (TapDownDetails details) {
|
||||||
|
tapDown += 1;
|
||||||
|
},
|
||||||
|
onTap: () {
|
||||||
|
tap += 1;
|
||||||
|
},
|
||||||
|
onTapCancel: () {
|
||||||
|
tapCancel += 1;
|
||||||
|
},
|
||||||
|
onLongPress: () {
|
||||||
|
longPress += 1;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Pointer is dragged from the center of the 800x100 gesture detector
|
||||||
|
// to a point (400,300) below it. This always causes onTapCancel to be
|
||||||
|
// called; onTap should never be called.
|
||||||
|
Future<Null> dragOut(Duration timeout) async {
|
||||||
|
final TestGesture gesture = await tester.startGesture(const Offset(400.0, 50.0));
|
||||||
|
// If the timeout is less than kPressTimout the recognizer will just trigger
|
||||||
|
// the onTapCancel callback. If the timeout is greater than kLongPressTimeout
|
||||||
|
// then onTapDown, onLongPress, and onCancel will be called.
|
||||||
|
await tester.pump(timeout);
|
||||||
|
await gesture.moveTo(const Offset(400.0, 300.0));
|
||||||
|
await gesture.up();
|
||||||
|
}
|
||||||
|
|
||||||
|
await dragOut(kPressTimeout * 0.5); // generates tapCancel
|
||||||
|
expect(tapDown, 0);
|
||||||
|
expect(tapCancel, 1);
|
||||||
|
expect(tap, 0);
|
||||||
|
expect(longPress, 0);
|
||||||
|
|
||||||
|
await dragOut(kPressTimeout); // generates tapDown, tapCancel
|
||||||
|
expect(tapDown, 1);
|
||||||
|
expect(tapCancel, 2);
|
||||||
|
expect(tap, 0);
|
||||||
|
expect(longPress, 0);
|
||||||
|
|
||||||
|
await dragOut(kLongPressTimeout); // generates tapDown, longPress, tapCancel
|
||||||
|
expect(tapDown, 2);
|
||||||
|
expect(tapCancel, 3);
|
||||||
|
expect(tap, 0);
|
||||||
|
expect(longPress, 1);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user