Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Add flag to ThemeData to expand tap targets of certain material widgets #18369

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 42 commits into from
Jul 3, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
39cd943
add semantic container, selectability, and enabled state to chip
jonahwilliams May 25, 2018
cf8a1c3
add tests for chip semantics
jonahwilliams May 25, 2018
07d5e9b
Merge branch 'master' of github.com:flutter/flutter into a11y_16964
jonahwilliams May 29, 2018
42402a1
add more test coverage, make sure hasEnabledState is present
jonahwilliams May 29, 2018
be5801f
update tests and use canTap
jonahwilliams May 29, 2018
ef41d7f
increase tap target using outer padding
jonahwilliams May 30, 2018
2a9a87e
changed outer padding to outer constraints, update some tests
jonahwilliams May 31, 2018
5a90a0e
increase time picker height by 12dp to account for bigger flat button
jonahwilliams May 31, 2018
cdabb2e
Update button.dart
jonahwilliams May 31, 2018
d8a89ca
adjust minimum heights of other buttons and fix some tests
jonahwilliams Jun 1, 2018
423a093
Merge branch 'a11y_615' of github.com:jonahwilliams/flutter into a11y…
jonahwilliams Jun 1, 2018
985fdb6
temporarily turn off two failing tests
jonahwilliams Jun 1, 2018
5944354
Merge branch 'master' of github.com:flutter/flutter into a11y_16964
jonahwilliams Jun 1, 2018
6e79412
increase minimum touch target to 48x48
jonahwilliams Jun 1, 2018
c3fbe84
make outer constraints configurable
jonahwilliams Jun 2, 2018
21c2941
increase size of checkbox, switch, and radio button to 48 by 48 to co…
jonahwilliams Jun 10, 2018
d412128
add flag for expanding tap targets
jonahwilliams Jun 11, 2018
4bf34be
add smoke test for tap target size
jonahwilliams Jun 11, 2018
61c6e30
switch flag for enum
jonahwilliams Jun 11, 2018
8a3f125
merge a11y_615 into flag change
jonahwilliams Jun 11, 2018
7bb9ff9
merge material button tap target changes adjusted to use new flag
jonahwilliams Jun 11, 2018
3bf7bcf
Merge branch 'a11y_16964' into tap_target_flag
jonahwilliams Jun 11, 2018
e0b1f28
fix imports and remove public outerConstraints property of chip
jonahwilliams Jun 11, 2018
440c962
address comments
jonahwilliams Jun 11, 2018
a90b986
fix spelling and add switch statement in time picker
jonahwilliams Jun 11, 2018
dbf3dae
fix new wrapping in chip
jonahwilliams Jun 11, 2018
1174a2d
Merge remote-tracking branch 'origin/tap_size' into tap_target_flag
jonahwilliams Jun 11, 2018
53d3be6
update checkbox, radio, and switch to use additonalConstraints instea…
jonahwilliams Jun 11, 2018
0e08fe8
Wrap CheckboxListTile, RadioListTile, and SwitchListTile in a collaps…
jonahwilliams Jun 11, 2018
5fb4873
renamed MaterialTapTargetSize enums and add size tests for Checkbox, …
jonahwilliams Jun 11, 2018
090b3d2
add size tests to buttons, mini fab, and raw chip
jonahwilliams Jun 12, 2018
bb6c3ac
make Checkbox, Radio, and Switch take a MaterialTapTargetSize enum in…
jonahwilliams Jun 12, 2018
b26dafb
effects vs affects
jonahwilliams Jun 12, 2018
c8d8cf6
Merge branch 'master' of github.com:flutter/flutter into tap_target_flag
jonahwilliams Jun 13, 2018
2e205be
refactor all updated material widgets to take materialTapTargetSize a…
jonahwilliams Jun 13, 2018
a47e806
add redirecting render object
jonahwilliams Jun 18, 2018
5f475d8
merge with remote
jonahwilliams Jun 18, 2018
7e61552
Address comments
jonahwilliams Jun 19, 2018
190be7b
increase chip hit detection and address button comments
jonahwilliams Jun 19, 2018
df92deb
Add ink tests for raw material button
jonahwilliams Jun 22, 2018
0145ffb
add tests for material chip behavior
jonahwilliams Jun 22, 2018
fea5961
Merge branch 'master' of https://github.com/flutter/flutter into tap_…
jonahwilliams Jul 3, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 76 additions & 17 deletions packages/flutter/lib/src/material/button.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// found in the LICENSE file.

import 'package:flutter/foundation.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';

import 'button_theme.dart';
Expand All @@ -11,6 +12,7 @@ import 'constants.dart';
import 'ink_well.dart';
import 'material.dart';
import 'theme.dart';
import 'theme_data.dart';

/// Creates a button based on [Semantics], [Material], and [InkWell]
/// widgets.
Expand Down Expand Up @@ -38,13 +40,14 @@ class RawMaterialButton extends StatefulWidget {
this.elevation = 2.0,
this.highlightElevation = 8.0,
this.disabledElevation = 0.0,
this.outerPadding,
this.padding = EdgeInsets.zero,
this.constraints = const BoxConstraints(minWidth: 88.0, minHeight: 36.0),
this.shape = const RoundedRectangleBorder(),
this.animationDuration = kThemeChangeDuration,
MaterialTapTargetSize materialTapTargetSize,
this.child,
}) : assert(shape != null),
}) : this.materialTapTargetSize = materialTapTargetSize ?? MaterialTapTargetSize.padded,
assert(shape != null),
assert(elevation != null),
assert(highlightElevation != null),
assert(disabledElevation != null),
Expand All @@ -58,10 +61,6 @@ class RawMaterialButton extends StatefulWidget {
/// If this is set to null, the button will be disabled, see [enabled].
final VoidCallback onPressed;

/// Padding to increase the size of the gesture detector which doesn't
/// increase the visible material of the button.
final EdgeInsets outerPadding;

/// Called by the underlying [InkWell] widget's [InkWell.onHighlightChanged]
/// callback.
final ValueChanged<bool> onHighlightChanged;
Expand Down Expand Up @@ -138,6 +137,15 @@ class RawMaterialButton extends StatefulWidget {
/// property to a non-null value.
bool get enabled => onPressed != null;

/// Configures the minimum size of the tap target.
///
/// Defaults to [MaterialTapTargetSize.padded].
///
/// See also:
///
/// * [MaterialTapTargetSize], for a description of how this affects tap targets.
final MaterialTapTargetSize materialTapTargetSize;

@override
_RawMaterialButtonState createState() => new _RawMaterialButtonState();
}
Expand Down Expand Up @@ -186,18 +194,23 @@ class _RawMaterialButtonState extends State<RawMaterialButton> {
),
),
);

if (widget.outerPadding != null) {
result = new GestureDetector(
behavior: HitTestBehavior.translucent,
excludeFromSemantics: true,
onTap: widget.onPressed,
child: new Padding(
padding: widget.outerPadding,
child: result
),
);
BoxConstraints constraints;
switch (widget.materialTapTargetSize) {
case MaterialTapTargetSize.padded:
constraints = const BoxConstraints(minWidth: 48.0, minHeight: 48.0);
break;
case MaterialTapTargetSize.shrinkWrap:
constraints = const BoxConstraints();
break;
}
result = new _ButtonRedirectingHitDetectionWidget(
constraints: constraints,
child: new Center(
child: result,
widthFactor: 1.0,
heightFactor: 1.0,
),
);

return new Semantics(
container: true,
Expand Down Expand Up @@ -248,6 +261,7 @@ class MaterialButton extends StatelessWidget {
this.minWidth,
this.height,
this.padding,
this.materialTapTargetSize,
@required this.onPressed,
this.child
}) : super(key: key);
Expand Down Expand Up @@ -353,6 +367,15 @@ class MaterialButton extends StatelessWidget {
/// {@macro flutter.widgets.child}
final Widget child;

/// Configures the minimum size of the tap target.
///
/// Defaults to [ThemeData.materialTapTargetSize].
///
/// See also:
///
/// * [MaterialTapTargetSize], for a description of how this affects tap targets.
final MaterialTapTargetSize materialTapTargetSize;

/// Whether the button is enabled or disabled. Buttons are disabled by default. To
/// enable a button, set its [onPressed] property to a non-null value.
bool get enabled => onPressed != null;
Expand Down Expand Up @@ -412,6 +435,7 @@ class MaterialButton extends StatelessWidget {
),
shape: buttonTheme.shape,
child: child,
materialTapTargetSize: materialTapTargetSize ?? theme.materialTapTargetSize,
);
}

Expand All @@ -421,3 +445,38 @@ class MaterialButton extends StatelessWidget {
properties.add(new FlagProperty('enabled', value: enabled, ifFalse: 'disabled'));
}
}

/// Redirects the position passed to [RenderBox.hitTest] to the center of the widget.
///
/// The primary purpose of this widget is to allow padding around [Material] widgets
/// to trigger the child ink feature without increasing the size of the material.
class _ButtonRedirectingHitDetectionWidget extends SingleChildRenderObjectWidget {
const _ButtonRedirectingHitDetectionWidget({
Key key,
Widget child,
this.constraints
}) : super(key: key, child: child);

final BoxConstraints constraints;

@override
RenderObject createRenderObject(BuildContext context) {
return new _RenderButtonRedirectingHitDetection(constraints);
}

@override
void updateRenderObject(BuildContext context, covariant _RenderButtonRedirectingHitDetection renderObject) {
renderObject.additionalConstraints = constraints;
}
}

class _RenderButtonRedirectingHitDetection extends RenderConstrainedBox {
_RenderButtonRedirectingHitDetection (BoxConstraints additionalConstraints) : super(additionalConstraints: additionalConstraints);

@override
bool hitTest(HitTestResult result, {Offset position}) {
if (!size.contains(position))
return false;
return child.hitTest(result, position: size.center(Offset.zero));
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is an interesting approach.

Why can't we just make the single GestureDetector bigger though?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The GestureDetector/InkWell/Material is a delicate ecosystem.

InkWell (which contains the gesture detector) uses context to find a parent material where it draws the splashes. Any increase in the size of the gesture detector, which is sized by the material, necessarily increase the material size which would increase the visible appearance of the button.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, right, I forgot that buttons had their own Material...

Please add a test to make sure that only one of the GestureDetectors gets the pointer down event (which I believe this code does as you wrote it but it's something we should make sure we don't regress since it's so subtle).

Also please make sure there's a test that when you tap inside the button, the splash starts where you tapped, but when you tap outside the button, it starts wherever we decided it should start.

29 changes: 28 additions & 1 deletion packages/flutter/lib/src/material/checkbox.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import 'package:flutter/widgets.dart';
import 'constants.dart';
import 'debug.dart';
import 'theme.dart';
import 'theme_data.dart';
import 'toggleable.dart';

/// A material design checkbox.
Expand Down Expand Up @@ -58,6 +59,7 @@ class Checkbox extends StatefulWidget {
this.tristate = false,
@required this.onChanged,
this.activeColor,
this.materialTapTargetSize,
}) : assert(tristate != null),
assert(tristate || value != null),
super(key: key);
Expand Down Expand Up @@ -113,6 +115,15 @@ class Checkbox extends StatefulWidget {
/// If tristate is false (the default), [value] must not be null.
final bool tristate;

/// Configures the minimum size of the tap target.
///
/// Defaults to [ThemeData.materialTapTargetSize].
///
/// See also:
///
/// * [MaterialTapTargetSize], for a description of how this affects tap targets.
final MaterialTapTargetSize materialTapTargetSize;

/// The width of a checkbox widget.
static const double width = 18.0;

Expand All @@ -125,12 +136,23 @@ class _CheckboxState extends State<Checkbox> with TickerProviderStateMixin {
Widget build(BuildContext context) {
assert(debugCheckHasMaterial(context));
final ThemeData themeData = Theme.of(context);
Size size;
switch (widget.materialTapTargetSize ?? themeData.materialTapTargetSize) {
case MaterialTapTargetSize.padded:
size = const Size(2 * kRadialReactionRadius + 8.0, 2 * kRadialReactionRadius + 8.0);
break;
case MaterialTapTargetSize.shrinkWrap:
size = const Size(2 * kRadialReactionRadius, 2 * kRadialReactionRadius);
break;
}
final BoxConstraints additionalConstraints = new BoxConstraints.tight(size);
return new _CheckboxRenderObjectWidget(
value: widget.value,
tristate: widget.tristate,
activeColor: widget.activeColor ?? themeData.toggleableActiveColor,
inactiveColor: widget.onChanged != null ? themeData.unselectedWidgetColor : themeData.disabledColor,
onChanged: widget.onChanged,
additionalConstraints: additionalConstraints,
vsync: this,
);
}
Expand All @@ -145,6 +167,7 @@ class _CheckboxRenderObjectWidget extends LeafRenderObjectWidget {
@required this.inactiveColor,
@required this.onChanged,
@required this.vsync,
@required this.additionalConstraints,
}) : assert(tristate != null),
assert(tristate || value != null),
assert(activeColor != null),
Expand All @@ -158,6 +181,7 @@ class _CheckboxRenderObjectWidget extends LeafRenderObjectWidget {
final Color inactiveColor;
final ValueChanged<bool> onChanged;
final TickerProvider vsync;
final BoxConstraints additionalConstraints;

@override
_RenderCheckbox createRenderObject(BuildContext context) => new _RenderCheckbox(
Expand All @@ -167,6 +191,7 @@ class _CheckboxRenderObjectWidget extends LeafRenderObjectWidget {
inactiveColor: inactiveColor,
onChanged: onChanged,
vsync: vsync,
additionalConstraints: additionalConstraints,
);

@override
Expand All @@ -177,6 +202,7 @@ class _CheckboxRenderObjectWidget extends LeafRenderObjectWidget {
..activeColor = activeColor
..inactiveColor = inactiveColor
..onChanged = onChanged
..additionalConstraints = additionalConstraints
..vsync = vsync;
}
}
Expand All @@ -191,6 +217,7 @@ class _RenderCheckbox extends RenderToggleable {
bool tristate,
Color activeColor,
Color inactiveColor,
BoxConstraints additionalConstraints,
ValueChanged<bool> onChanged,
@required TickerProvider vsync,
}): _oldValue = value,
Expand All @@ -200,7 +227,7 @@ class _RenderCheckbox extends RenderToggleable {
activeColor: activeColor,
inactiveColor: inactiveColor,
onChanged: onChanged,
size: const Size(2 * kRadialReactionRadius, 2 * kRadialReactionRadius),
additionalConstraints: additionalConstraints,
vsync: vsync,
);

Expand Down
2 changes: 2 additions & 0 deletions packages/flutter/lib/src/material/checkbox_list_tile.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'package:flutter/widgets.dart';
import 'checkbox.dart';
import 'list_tile.dart';
import 'theme.dart';
import 'theme_data.dart';

/// A [ListTile] with a [Checkbox]. In other words, a checkbox with a label.
///
Expand Down Expand Up @@ -173,6 +174,7 @@ class CheckboxListTile extends StatelessWidget {
value: value,
onChanged: onChanged,
activeColor: activeColor,
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
);
Widget leading, trailing;
switch (controlAffinity) {
Expand Down
Loading