Unverified Commit a178bba5 authored by Rashid-Khabeer's avatar Rashid-Khabeer Committed by GitHub

Add onLongPress property to DataCell: #72609 (#75393)

parent 705cebb2
...@@ -206,6 +206,10 @@ class DataCell { ...@@ -206,6 +206,10 @@ class DataCell {
this.placeholder = false, this.placeholder = false,
this.showEditIcon = false, this.showEditIcon = false,
this.onTap, this.onTap,
this.onLongPress,
this.onTapDown,
this.onDoubleTap,
this.onTapCancel,
}) : assert(child != null); }) : assert(child != null);
/// A cell that has no content and has zero width and height. /// A cell that has no content and has zero width and height.
...@@ -241,14 +245,48 @@ class DataCell { ...@@ -241,14 +245,48 @@ class DataCell {
/// Called if the cell is tapped. /// Called if the cell is tapped.
/// ///
/// If non-null, tapping the cell will call this callback. If /// If non-null, tapping the cell will call this callback. If
/// null, tapping the cell will attempt to select the row (if /// null (including [onDoubleTap], [onLongPress], [onTapCancel] and [onTapDown]),
/// tapping the cell will attempt to select the row (if
/// [DataRow.onSelectChanged] is provided). /// [DataRow.onSelectChanged] is provided).
final GestureTapCallback? onTap;
/// Called when the cell is double tapped.
///
/// If non-null, tapping the cell will call this callback. If
/// null (including [onTap], [onLongPress], [onTapCancel] and [onTapDown]),
/// tapping the cell will attempt to select the row (if
/// [DataRow.onSelectChanged] is provided).
final GestureTapCallback? onDoubleTap;
/// Called if the cell is long-pressed.
///
/// If non-null, tapping the cell will invoke this callback. If
/// null (including [onDoubleTap], [onTap], [onTapCancel] and [onTapDown]),
/// tapping the cell will attempt to select the row (if
/// [DataRow.onSelectChanged] is provided).
final GestureLongPressCallback? onLongPress;
/// Called if the cell is tapped down.
/// ///
/// To define a tap behavior for the entire row, see /// If non-null, tapping the cell will call this callback. If
/// [DataRow.onSelectChanged]. /// null (including [onTap] [onDoubleTap], [onLongPress] and [onTapCancel]),
final VoidCallback? onTap; /// tapping the cell will attempt to select the row (if
/// [DataRow.onSelectChanged] is provided).
final GestureTapDownCallback? onTapDown;
bool get _debugInteractive => onTap != null; /// Called if the user cancels a tap was started on cell.
///
/// If non-null, cancelling the tap gesture will invoke this callback.
/// If null (including [onTap], [onDoubleTap] and [onLongPress]),
/// tapping the cell will attempt to select the
/// row (if [DataRow.onSelectChanged] is provided).
final GestureTapCancelCallback? onTapCancel;
bool get _debugInteractive => onTap != null ||
onDoubleTap != null ||
onLongPress != null ||
onTapDown != null ||
onTapCancel != null;
} }
/// A material design data table. /// A material design data table.
...@@ -809,8 +847,12 @@ class DataTable extends StatelessWidget { ...@@ -809,8 +847,12 @@ class DataTable extends StatelessWidget {
required bool numeric, required bool numeric,
required bool placeholder, required bool placeholder,
required bool showEditIcon, required bool showEditIcon,
required VoidCallback? onTap, required GestureTapCallback? onTap,
required VoidCallback? onSelectChanged, required VoidCallback? onSelectChanged,
required GestureTapCallback? onDoubleTap,
required GestureLongPressCallback? onLongPress,
required GestureTapDownCallback? onTapDown,
required GestureTapCancelCallback? onTapCancel,
required MaterialStateProperty<Color?>? overlayColor, required MaterialStateProperty<Color?>? overlayColor,
}) { }) {
final ThemeData themeData = Theme.of(context); final ThemeData themeData = Theme.of(context);
...@@ -840,9 +882,17 @@ class DataTable extends StatelessWidget { ...@@ -840,9 +882,17 @@ class DataTable extends StatelessWidget {
child: DropdownButtonHideUnderline(child: label), child: DropdownButtonHideUnderline(child: label),
), ),
); );
if (onTap != null) { if (onTap != null ||
onDoubleTap != null ||
onLongPress != null ||
onTapDown != null ||
onTapCancel != null) {
label = InkWell( label = InkWell(
onTap: onTap, onTap: onTap,
onDoubleTap: onDoubleTap,
onLongPress: onLongPress,
onTapCancel: onTapCancel,
onTapDown: onTapDown,
child: label, child: label,
overlayColor: overlayColor, overlayColor: overlayColor,
); );
...@@ -1000,6 +1050,10 @@ class DataTable extends StatelessWidget { ...@@ -1000,6 +1050,10 @@ class DataTable extends StatelessWidget {
placeholder: cell.placeholder, placeholder: cell.placeholder,
showEditIcon: cell.showEditIcon, showEditIcon: cell.showEditIcon,
onTap: cell.onTap, onTap: cell.onTap,
onDoubleTap: cell.onDoubleTap,
onLongPress: cell.onLongPress,
onTapCancel: cell.onTapCancel,
onTapDown: cell.onTapDown,
onSelectChanged: () => row.onSelectChanged != null ? row.onSelectChanged!(!row.selected) : null, onSelectChanged: () => row.onSelectChanged != null ? row.onSelectChanged!(!row.selected) : null,
overlayColor: row.color ?? effectiveDataRowColor, overlayColor: row.color ?? effectiveDataRowColor,
); );
......
...@@ -54,6 +54,18 @@ void main() { ...@@ -54,6 +54,18 @@ void main() {
onTap: () { onTap: () {
log.add('cell-tap: ${dessert.calories}'); log.add('cell-tap: ${dessert.calories}');
}, },
onDoubleTap: () {
log.add('cell-doubleTap: ${dessert.calories}');
},
onLongPress: () {
log.add('cell-longPress: ${dessert.calories}');
},
onTapCancel: () {
log.add('cell-tapCancel: ${dessert.calories}');
},
onTapDown: (TapDownDetails details) {
log.add('cell-tapDown: ${dessert.calories}');
},
), ),
], ],
); );
...@@ -95,8 +107,40 @@ void main() { ...@@ -95,8 +107,40 @@ void main() {
await tester.pumpAndSettle(const Duration(milliseconds: 200)); await tester.pumpAndSettle(const Duration(milliseconds: 200));
await tester.tap(find.text('375')); await tester.tap(find.text('375'));
await tester.pump(const Duration(milliseconds: 100));
await tester.tap(find.text('375'));
expect(log, <String>['cell-doubleTap: 375']);
log.clear();
await tester.longPress(find.text('375'));
// The tap down is triggered on gesture down.
// Then, the cancel is triggered when the gesture arena
// recognizes that the long press overrides the tap event
// so it triggers a tap cancel, followed by the long press.
expect(log,<String>['cell-tapDown: 375' ,'cell-tapCancel: 375', 'cell-longPress: 375']);
log.clear();
TestGesture gesture = await tester.startGesture(
tester.getRect(find.text('375')).center,
);
await tester.pump(const Duration(milliseconds: 100));
// onTapDown callback is registered.
expect(log, equals(<String>['cell-tapDown: 375']));
await gesture.up();
await tester.pump(const Duration(seconds: 1));
// onTap callback is registered after the gesture is removed.
expect(log, equals(<String>['cell-tapDown: 375', 'cell-tap: 375']));
log.clear();
// dragging off the bounds of the cell calls the cancel callback
gesture = await tester.startGesture(tester.getRect(find.text('375')).center);
await tester.pump(const Duration(milliseconds: 100));
await gesture.moveBy(const Offset(0.0, 200.0));
await gesture.cancel();
expect(log, equals(<String>['cell-tapDown: 375', 'cell-tapCancel: 375']));
expect(log, <String>['cell-tap: 375']);
log.clear(); log.clear();
await tester.tap(find.byType(Checkbox).last); await tester.tap(find.byType(Checkbox).last);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment