Unverified Commit 0b216f7a authored by Taha Tesser's avatar Taha Tesser Committed by GitHub

Refactor `ToggleButtons` (remove `RawMaterialButton`) (#99493)

parent 0e20a701
...@@ -8,11 +8,12 @@ import 'package:flutter/foundation.dart'; ...@@ -8,11 +8,12 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'button.dart'; import 'button_style.dart';
import 'color_scheme.dart'; import 'color_scheme.dart';
import 'constants.dart'; import 'constants.dart';
import 'debug.dart'; import 'ink_ripple.dart';
import 'material_state.dart'; import 'material_state.dart';
import 'text_button.dart';
import 'theme.dart'; import 'theme.dart';
import 'theme_data.dart'; import 'theme_data.dart';
import 'toggle_buttons_theme.dart'; import 'toggle_buttons_theme.dart';
...@@ -192,10 +193,21 @@ class ToggleButtons extends StatelessWidget { ...@@ -192,10 +193,21 @@ class ToggleButtons extends StatelessWidget {
this.borderWidth, this.borderWidth,
this.direction = Axis.horizontal, this.direction = Axis.horizontal,
this.verticalDirection = VerticalDirection.down, this.verticalDirection = VerticalDirection.down,
this.style,
}) : }) :
assert(children != null), assert(children != null),
assert(isSelected != null), assert(isSelected != null),
assert(children.length == isSelected.length), assert(children.length == isSelected.length),
assert(
!(style != null
&& (mouseCursor != null
|| textStyle != null
|| fillColor != null
|| focusColor != null
|| highlightColor != null
|| hoverColor != null
|| splashColor != null)),
'You can only pass [style] or textStyle, fillColor, splashColor properties, not both.'),
assert(direction != null), assert(direction != null),
assert(direction == Axis.horizontal || verticalDirection != null), assert(direction == Axis.horizontal || verticalDirection != null),
super(key: key); super(key: key);
...@@ -417,6 +429,14 @@ class ToggleButtons extends StatelessWidget { ...@@ -417,6 +429,14 @@ class ToggleButtons extends StatelessWidget {
/// the buttons starting from the first or last child from top to bottom. /// the buttons starting from the first or last child from top to bottom.
final VerticalDirection verticalDirection; final VerticalDirection verticalDirection;
/// Customizes this toggle button's appearance.
///
/// When implemented this overrides the individual customizable properties
/// of toggle buttons such as [selectedColor], [disabledColor], [hoverColor].
///
/// Null by default.
final ButtonStyle? style;
// Determines if this is the first child that is being laid out // Determines if this is the first child that is being laid out
// by the render object, _not_ the order of the children in its list. // by the render object, _not_ the order of the children in its list.
bool _isFirstButton(int index, int length, TextDirection textDirection) { bool _isFirstButton(int index, int length, TextDirection textDirection) {
...@@ -668,33 +688,87 @@ class ToggleButtons extends StatelessWidget { ...@@ -668,33 +688,87 @@ class ToggleButtons extends StatelessWidget {
final BorderSide borderSide = _getBorderSide(index, theme, toggleButtonsTheme); final BorderSide borderSide = _getBorderSide(index, theme, toggleButtonsTheme);
final BorderSide trailingBorderSide = _getTrailingBorderSide(index, theme, toggleButtonsTheme); final BorderSide trailingBorderSide = _getTrailingBorderSide(index, theme, toggleButtonsTheme);
return _ToggleButton( final Set<MaterialState> states = <MaterialState>{
selected: isSelected[index], if (isSelected[index] && onPressed != null) MaterialState.selected,
textStyle: textStyle, if (onPressed == null) MaterialState.disabled,
constraints: constraints, };
color: color, final Color effectiveFillColor = _ResolveFillColor(fillColor
selectedColor: selectedColor, ?? toggleButtonsTheme.fillColor).resolve(states)
disabledColor: disabledColor, ?? _DefaultFillColor(theme.colorScheme).resolve(states);
fillColor: fillColor, final Color currentColor;
focusColor: focusColor ?? toggleButtonsTheme.focusColor, if (onPressed != null && isSelected[index]) {
highlightColor: highlightColor ?? toggleButtonsTheme.highlightColor, currentColor = selectedColor
hoverColor: hoverColor ?? toggleButtonsTheme.hoverColor, ?? toggleButtonsTheme.selectedColor
splashColor: splashColor ?? toggleButtonsTheme.splashColor, ?? theme.colorScheme.primary;
focusNode: focusNodes != null ? focusNodes![index] : null, } else if (onPressed != null && !isSelected[index]) {
onPressed: onPressed != null currentColor = color
? () {onPressed!(index);} ?? toggleButtonsTheme.color
: null, ?? theme.colorScheme.onSurface.withOpacity(0.87);
mouseCursor: mouseCursor, } else {
currentColor = disabledColor
?? toggleButtonsTheme.disabledColor
?? theme.colorScheme.onSurface.withOpacity(0.38);
}
final TextStyle currentTextStyle = textStyle
?? toggleButtonsTheme.textStyle
?? theme.textTheme.bodyText2!;
final BoxConstraints currentConstraints = constraints
?? toggleButtonsTheme.constraints
?? const BoxConstraints(
minWidth: kMinInteractiveDimension,
minHeight: kMinInteractiveDimension,
);
return _SelectToggleButton(
leadingBorderSide: leadingBorderSide, leadingBorderSide: leadingBorderSide,
borderSide: borderSide, borderSide: borderSide,
trailingBorderSide: trailingBorderSide, trailingBorderSide: trailingBorderSide,
borderRadius: edgeBorderRadius, borderRadius: edgeBorderRadius,
clipRadius: clipBorderRadius,
isFirstButton: index == 0, isFirstButton: index == 0,
isLastButton: index == children.length - 1, isLastButton: index == children.length - 1,
direction: direction, direction: direction,
verticalDirection: verticalDirection, verticalDirection: verticalDirection,
child: children[index], child: ClipRRect(
borderRadius: clipBorderRadius,
child: TextButton(
focusNode: focusNodes != null ? focusNodes![index] : null,
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all<Color?>(effectiveFillColor),
foregroundColor: MaterialStateProperty.all<Color?>(currentColor),
overlayColor: _ToggleButtonDefaultOverlay(
selected: onPressed != null && isSelected[index],
unselected: onPressed != null && !isSelected[index],
colorScheme: theme.colorScheme,
disabledColor: disabledColor ?? toggleButtonsTheme.disabledColor,
focusColor: focusColor ?? toggleButtonsTheme.focusColor,
highlightColor: highlightColor ?? toggleButtonsTheme.highlightColor,
hoverColor: hoverColor ?? toggleButtonsTheme.hoverColor,
splashColor: splashColor ?? toggleButtonsTheme.splashColor,
),
elevation: MaterialStateProperty.all<double>(0),
textStyle: MaterialStateProperty.all<TextStyle?>(currentTextStyle.copyWith(
color: currentColor,
)),
padding: MaterialStateProperty.all<EdgeInsetsGeometry>(EdgeInsets.zero),
minimumSize: MaterialStateProperty.all<Size?>(
Size(currentConstraints.minWidth, currentConstraints.minHeight)),
maximumSize: MaterialStateProperty.all<Size?>(
Size(currentConstraints.maxWidth, currentConstraints.maxHeight)),
shape: MaterialStateProperty.all<OutlinedBorder>(const RoundedRectangleBorder()),
mouseCursor: MaterialStateProperty.all<MouseCursor?>(mouseCursor),
visualDensity: VisualDensity.adaptivePlatformDensity,
tapTargetSize: tapTargetSize ?? theme.materialTapTargetSize,
animationDuration: kThemeChangeDuration,
enableFeedback: true,
alignment: Alignment.center,
splashFactory: InkRipple.splashFactory,
),
onPressed: onPressed != null
? () {onPressed!(index);}
: null,
child: children[index],
),
),
); );
}); });
...@@ -715,17 +789,7 @@ class ToggleButtons extends StatelessWidget { ...@@ -715,17 +789,7 @@ class ToggleButtons extends StatelessWidget {
), ),
); );
final MaterialTapTargetSize resolvedTapTargetSize = tapTargetSize ?? theme.materialTapTargetSize; return result;
switch (resolvedTapTargetSize) {
case MaterialTapTargetSize.padded:
return _InputPadding(
minSize: const Size(kMinInteractiveDimension, kMinInteractiveDimension),
direction: direction,
child: result,
);
case MaterialTapTargetSize.shrinkWrap:
return result;
}
} }
@override @override
...@@ -755,251 +819,6 @@ class ToggleButtons extends StatelessWidget { ...@@ -755,251 +819,6 @@ class ToggleButtons extends StatelessWidget {
} }
} }
/// An individual toggle button, otherwise known as a segmented button.
///
/// This button is used by [ToggleButtons] to implement a set of segmented controls.
class _ToggleButton extends StatelessWidget {
/// Creates a toggle button based on [RawMaterialButton].
///
/// This class adds some logic to distinguish between enabled, active, and
/// disabled states, to determine the appropriate colors to use.
///
/// It takes in a [shape] property to modify the borders of the button,
/// which is used by [ToggleButtons] to customize borders based on the
/// order in which this button appears in the list.
const _ToggleButton({
Key? key,
this.selected = false,
this.textStyle,
this.constraints,
this.color,
this.selectedColor,
this.disabledColor,
required this.fillColor,
required this.focusColor,
required this.highlightColor,
required this.hoverColor,
required this.splashColor,
this.focusNode,
this.onPressed,
this.mouseCursor,
required this.leadingBorderSide,
required this.borderSide,
required this.trailingBorderSide,
required this.borderRadius,
required this.clipRadius,
required this.isFirstButton,
required this.isLastButton,
required this.direction,
required this.verticalDirection,
required this.child,
}) : super(key: key);
/// Determines if the button is displayed as active/selected or enabled.
final bool selected;
/// The [TextStyle] to apply to any text that appears in this button.
final TextStyle? textStyle;
/// Defines the button's size.
///
/// Typically used to constrain the button's minimum size.
final BoxConstraints? constraints;
/// The color for [Text] and [Icon] widgets if the button is enabled.
///
/// If [selected] is false and [onPressed] is not null, this color will be used.
final Color? color;
/// The color for [Text] and [Icon] widgets if the button is selected.
///
/// If [selected] is true and [onPressed] is not null, this color will be used.
final Color? selectedColor;
/// The color for [Text] and [Icon] widgets if the button is disabled.
///
/// If [onPressed] is null, this color will be used.
final Color? disabledColor;
/// The color of the button's [Material].
final Color? fillColor;
/// The color for the button's [Material] when it has the input focus.
final Color? focusColor;
/// The color for the button's [Material] when a pointer is hovering over it.
final Color? hoverColor;
/// The highlight color for the button's [InkWell].
final Color? highlightColor;
/// The splash color for the button's [InkWell].
final Color? splashColor;
/// {@macro flutter.widgets.Focus.focusNode}
final FocusNode? focusNode;
/// Called when the button is tapped or otherwise activated.
///
/// If this is null, the button will be disabled, see [enabled].
final VoidCallback? onPressed;
/// {@macro flutter.material.RawMaterialButton.mouseCursor}
///
/// If this property is null, [MaterialStateMouseCursor.clickable] will be used.
final MouseCursor? mouseCursor;
/// The width and color of the button's leading side border.
final BorderSide leadingBorderSide;
/// If [direction] is [Axis.horizontal], this corresponds the width and color
/// of the button's top and bottom side borders.
///
/// If [direction] is [Axis.vertical], this corresponds the width and color
/// of the button's left and right side borders.
final BorderSide borderSide;
/// The width and color of the button's trailing side border.
final BorderSide trailingBorderSide;
/// The border radii of each corner of the button.
final BorderRadius borderRadius;
/// The corner radii used to clip the button's contents.
///
/// This is used to have the button's contents be properly clipped taking
/// the [borderRadius] and the border's width into account.
final BorderRadius clipRadius;
/// Whether or not this toggle button is the first button in the list.
final bool isFirstButton;
/// Whether or not this toggle button is the last button in the list.
final bool isLastButton;
/// The direction along which the buttons are rendered.
final Axis direction;
/// If [direction] is [Axis.vertical], this property defines whether or not this button in its list
/// of buttons is laid out starting from top to bottom or from bottom to top.
final VerticalDirection verticalDirection;
/// The button's label, which is usually an [Icon] or a [Text] widget.
final Widget child;
Color _resolveColor(Set<MaterialState> states, MaterialStateProperty<Color?> widgetColor,
MaterialStateProperty<Color?> themeColor, MaterialStateProperty<Color> defaultColor) {
return widgetColor.resolve(states)
?? themeColor.resolve(states)
?? defaultColor.resolve(states);
}
@override
Widget build(BuildContext context) {
assert(debugCheckHasMaterial(context));
final Color currentColor;
Color? currentFocusColor;
Color? currentHoverColor;
Color? currentSplashColor;
final ThemeData theme = Theme.of(context);
final ToggleButtonsThemeData toggleButtonsTheme = ToggleButtonsTheme.of(context);
final Set<MaterialState> states = <MaterialState>{
if (selected && onPressed != null) MaterialState.selected,
if (onPressed == null) MaterialState.disabled,
};
final Color currentFillColor = _resolveColor(
states,
_ResolveFillColor(fillColor),
_ResolveFillColor(toggleButtonsTheme.fillColor),
_DefaultFillColor(theme.colorScheme),
);
if (onPressed != null && selected) {
currentColor = selectedColor
?? toggleButtonsTheme.selectedColor
?? theme.colorScheme.primary;
currentFocusColor = focusColor
?? toggleButtonsTheme.focusColor
?? theme.colorScheme.primary.withOpacity(0.12);
currentHoverColor = hoverColor
?? toggleButtonsTheme.hoverColor
?? theme.colorScheme.primary.withOpacity(0.04);
currentSplashColor = splashColor
?? toggleButtonsTheme.splashColor
?? theme.colorScheme.primary.withOpacity(0.16);
} else if (onPressed != null && !selected) {
currentColor = color
?? toggleButtonsTheme.color
?? theme.colorScheme.onSurface.withOpacity(0.87);
currentFocusColor = focusColor
?? toggleButtonsTheme.focusColor
?? theme.colorScheme.onSurface.withOpacity(0.12);
currentHoverColor = hoverColor
?? toggleButtonsTheme.hoverColor
?? theme.colorScheme.onSurface.withOpacity(0.04);
currentSplashColor = splashColor
?? toggleButtonsTheme.splashColor
?? theme.colorScheme.onSurface.withOpacity(0.16);
} else {
currentColor = disabledColor
?? toggleButtonsTheme.disabledColor
?? theme.colorScheme.onSurface.withOpacity(0.38);
}
final TextStyle currentTextStyle = textStyle ?? toggleButtonsTheme.textStyle ?? theme.textTheme.bodyText2!;
final BoxConstraints currentConstraints = constraints ?? toggleButtonsTheme.constraints ?? const BoxConstraints(minWidth: kMinInteractiveDimension, minHeight: kMinInteractiveDimension);
final Widget result = ClipRRect(
borderRadius: clipRadius,
child: RawMaterialButton(
textStyle: currentTextStyle.copyWith(
color: currentColor,
),
constraints: currentConstraints,
elevation: 0.0,
fillColor: currentFillColor,
focusColor: currentFocusColor,
focusElevation: 0,
highlightColor: highlightColor ?? theme.colorScheme.surface.withOpacity(0.0),
highlightElevation: 0.0,
hoverColor: currentHoverColor,
hoverElevation: 0,
splashColor: currentSplashColor,
focusNode: focusNode,
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
onPressed: onPressed,
mouseCursor: mouseCursor,
child: child,
),
);
return _SelectToggleButton(
key: key,
leadingBorderSide: leadingBorderSide,
borderSide: borderSide,
trailingBorderSide: trailingBorderSide,
borderRadius: borderRadius,
isFirstButton: isFirstButton,
isLastButton: isLastButton,
direction: direction,
verticalDirection: verticalDirection,
child: result,
);
}
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.add(FlagProperty('selected',
value: selected,
ifTrue: 'Button is selected',
ifFalse: 'Button is unselected',
));
}
}
@immutable @immutable
class _ResolveFillColor extends MaterialStateProperty<Color?> with Diagnosticable { class _ResolveFillColor extends MaterialStateProperty<Color?> with Diagnosticable {
_ResolveFillColor(this.primary); _ResolveFillColor(this.primary);
...@@ -1030,6 +849,68 @@ class _DefaultFillColor extends MaterialStateProperty<Color> with Diagnosticable ...@@ -1030,6 +849,68 @@ class _DefaultFillColor extends MaterialStateProperty<Color> with Diagnosticable
} }
} }
@immutable
class _ToggleButtonDefaultOverlay extends MaterialStateProperty<Color?> {
_ToggleButtonDefaultOverlay({
required this.selected,
required this.unselected,
this.colorScheme,
this.focusColor,
this.highlightColor,
this.hoverColor,
this.splashColor,
this.disabledColor,
});
final bool selected;
final bool unselected;
final ColorScheme? colorScheme;
final Color? focusColor;
final Color? highlightColor;
final Color? hoverColor;
final Color? splashColor;
final Color? disabledColor;
@override
Color? resolve(Set<MaterialState> states) {
if (selected) {
if (states.contains(MaterialState.hovered)) {
return hoverColor ?? colorScheme?.primary.withOpacity(0.04);
} else if (states.contains(MaterialState.focused)) {
return focusColor ?? colorScheme?.primary.withOpacity(0.12);
} else if (states.contains(MaterialState.pressed)) {
return splashColor ?? colorScheme?.primary.withOpacity(0.16);
}
} else if (unselected) {
if (states.contains(MaterialState.hovered)) {
return hoverColor ?? colorScheme?.onSurface.withOpacity(0.04);
} else if (states.contains(MaterialState.focused)) {
return focusColor ?? colorScheme?.onSurface.withOpacity(0.12);
} else if (states.contains(MaterialState.pressed)) {
return splashColor ?? highlightColor ?? colorScheme?.onSurface.withOpacity(0.16);
}
}
return null;
}
@override
String toString() {
return '''
{
selected:
hovered: $hoverColor, otherwise: ${colorScheme?.primary.withOpacity(0.04)},
focused: $focusColor, otherwise: ${colorScheme?.primary.withOpacity(0.12)},
pressed: $splashColor, otherwise: ${colorScheme?.primary.withOpacity(0.16)},
unselected:
hovered: $hoverColor, otherwise: ${colorScheme?.onSurface.withOpacity(0.04)},
focused: $focusColor, otherwise: ${colorScheme?.onSurface.withOpacity(0.12)},
pressed: $splashColor, otherwise: ${colorScheme?.onSurface.withOpacity(0.16)},
otherwise: null,
}
''';
}
}
class _SelectToggleButton extends SingleChildRenderObjectWidget { class _SelectToggleButton extends SingleChildRenderObjectWidget {
const _SelectToggleButton({ const _SelectToggleButton({
Key? key, Key? key,
...@@ -1576,141 +1457,3 @@ class _SelectToggleButtonRenderObject extends RenderShiftedBox { ...@@ -1576,141 +1457,3 @@ class _SelectToggleButtonRenderObject extends RenderShiftedBox {
} }
} }
} }
/// A widget to pad the area around a [ToggleButtons]'s children.
///
/// This widget is based on a similar one used in [ButtonStyleButton] but it
/// only redirects taps along one axis to ensure the correct button is tapped
/// within the [ToggleButtons].
///
/// This ensures that a widget takes up at least as much space as the minSize
/// parameter to ensure adequate tap target size, while keeping the widget
/// visually smaller to the user.
class _InputPadding extends SingleChildRenderObjectWidget {
const _InputPadding({
Key? key,
Widget? child,
required this.minSize,
required this.direction,
}) : super(key: key, child: child);
final Size minSize;
final Axis direction;
@override
RenderObject createRenderObject(BuildContext context) {
return _RenderInputPadding(minSize, direction);
}
@override
void updateRenderObject(BuildContext context, covariant _RenderInputPadding renderObject) {
renderObject.minSize = minSize;
renderObject.direction = direction;
}
}
class _RenderInputPadding extends RenderShiftedBox {
_RenderInputPadding(this._minSize, this._direction, [RenderBox? child]) : super(child);
Size get minSize => _minSize;
Size _minSize;
set minSize(Size value) {
if (_minSize == value)
return;
_minSize = value;
markNeedsLayout();
}
Axis get direction => _direction;
Axis _direction;
set direction(Axis value) {
if (_direction == value)
return;
_direction = value;
markNeedsLayout();
}
@override
double computeMinIntrinsicWidth(double height) {
if (child != null)
return math.max(child!.getMinIntrinsicWidth(height), minSize.width);
return 0.0;
}
@override
double computeMinIntrinsicHeight(double width) {
if (child != null)
return math.max(child!.getMinIntrinsicHeight(width), minSize.height);
return 0.0;
}
@override
double computeMaxIntrinsicWidth(double height) {
if (child != null)
return math.max(child!.getMaxIntrinsicWidth(height), minSize.width);
return 0.0;
}
@override
double computeMaxIntrinsicHeight(double width) {
if (child != null)
return math.max(child!.getMaxIntrinsicHeight(width), minSize.height);
return 0.0;
}
Size _computeSize({required BoxConstraints constraints, required ChildLayouter layoutChild}) {
if (child != null) {
final Size childSize = layoutChild(child!, constraints);
final double height = math.max(childSize.width, minSize.width);
final double width = math.max(childSize.height, minSize.height);
return constraints.constrain(Size(height, width));
}
return Size.zero;
}
@override
Size computeDryLayout(BoxConstraints constraints) {
return _computeSize(
constraints: constraints,
layoutChild: ChildLayoutHelper.dryLayoutChild,
);
}
@override
void performLayout() {
size = _computeSize(
constraints: constraints,
layoutChild: ChildLayoutHelper.layoutChild,
);
if (child != null) {
final BoxParentData childParentData = child!.parentData! as BoxParentData;
childParentData.offset = Alignment.center.alongOffset(size - child!.size as Offset);
}
}
@override
bool hitTest(BoxHitTestResult result, { required Offset position }) {
// The super.hitTest() method also checks hitTestChildren(). We don't
// want that in this case because we've padded around the children per
// tapTargetSize.
if (!size.contains(position)) {
return false;
}
// Only adjust one axis to ensure the correct button is tapped.
Offset center;
if (direction == Axis.horizontal) {
center = Offset(position.dx, child!.size.height / 2);
} else {
center = Offset(child!.size.width / 2, position.dy);
}
return result.addWithRawTransform(
transform: MatrixUtils.forceToPoint(center),
position: center,
hitTest: (BoxHitTestResult result, Offset position) {
assert(position == center);
return child!.hitTest(result, position: center);
},
);
}
}
...@@ -26,7 +26,7 @@ void main() { ...@@ -26,7 +26,7 @@ void main() {
testWidgets('Initial toggle state is reflected', (WidgetTester tester) async { testWidgets('Initial toggle state is reflected', (WidgetTester tester) async {
TextStyle buttonTextStyle(String text) { TextStyle buttonTextStyle(String text) {
return tester.widget<DefaultTextStyle>(find.descendant( return tester.widget<DefaultTextStyle>(find.descendant(
of: find.widgetWithText(RawMaterialButton, text), of: find.widgetWithText(TextButton, text),
matching: find.byType(DefaultTextStyle), matching: find.byType(DefaultTextStyle),
)).style; )).style;
} }
...@@ -61,11 +61,10 @@ void main() { ...@@ -61,11 +61,10 @@ void main() {
(WidgetTester tester) async { (WidgetTester tester) async {
TextStyle buttonTextStyle(String text) { TextStyle buttonTextStyle(String text) {
return tester.widget<DefaultTextStyle>(find.descendant( return tester.widget<DefaultTextStyle>(find.descendant(
of: find.widgetWithText(RawMaterialButton, text), of: find.widgetWithText(TextButton, text),
matching: find.byType(DefaultTextStyle), matching: find.byType(DefaultTextStyle),
)).style; )).style;
} }
final List<bool> isSelected = <bool>[false, true]; final List<bool> isSelected = <bool>[false, true];
final ThemeData theme = ThemeData(); final ThemeData theme = ThemeData();
await tester.pumpWidget( await tester.pumpWidget(
...@@ -123,7 +122,7 @@ void main() { ...@@ -123,7 +122,7 @@ void main() {
(WidgetTester tester) async { (WidgetTester tester) async {
TextStyle buttonTextStyle(String text) { TextStyle buttonTextStyle(String text) {
return tester.widget<DefaultTextStyle>(find.descendant( return tester.widget<DefaultTextStyle>(find.descendant(
of: find.widgetWithText(RawMaterialButton, text), of: find.widgetWithText(TextButton, text),
matching: find.byType(DefaultTextStyle), matching: find.byType(DefaultTextStyle),
)).style; )).style;
} }
...@@ -220,14 +219,14 @@ void main() { ...@@ -220,14 +219,14 @@ void main() {
TextStyle textStyle; TextStyle textStyle;
textStyle = tester.widget<DefaultTextStyle>(find.descendant( textStyle = tester.widget<DefaultTextStyle>(find.descendant(
of: find.widgetWithText(RawMaterialButton, 'First child'), of: find.widgetWithText(TextButton, 'First child'),
matching: find.byType(DefaultTextStyle), matching: find.byType(DefaultTextStyle),
)).style; )).style;
expect(textStyle.fontFamily, theme.textTheme.bodyText2!.fontFamily); expect(textStyle.fontFamily, theme.textTheme.bodyText2!.fontFamily);
expect(textStyle.decoration, theme.textTheme.bodyText2!.decoration); expect(textStyle.decoration, theme.textTheme.bodyText2!.decoration);
textStyle = tester.widget<DefaultTextStyle>(find.descendant( textStyle = tester.widget<DefaultTextStyle>(find.descendant(
of: find.widgetWithText(RawMaterialButton, 'Second child'), of: find.widgetWithText(TextButton, 'Second child'),
matching: find.byType(DefaultTextStyle), matching: find.byType(DefaultTextStyle),
)).style; )).style;
expect(textStyle.fontFamily, theme.textTheme.bodyText2!.fontFamily); expect(textStyle.fontFamily, theme.textTheme.bodyText2!.fontFamily);
...@@ -257,7 +256,7 @@ void main() { ...@@ -257,7 +256,7 @@ void main() {
TextStyle textStyle; TextStyle textStyle;
textStyle = tester.widget<DefaultTextStyle>(find.descendant( textStyle = tester.widget<DefaultTextStyle>(find.descendant(
of: find.widgetWithText(RawMaterialButton, 'First child'), of: find.widgetWithText(TextButton, 'First child'),
matching: find.byType(DefaultTextStyle), matching: find.byType(DefaultTextStyle),
)).style; )).style;
expect(textStyle.textBaseline, TextBaseline.ideographic); expect(textStyle.textBaseline, TextBaseline.ideographic);
...@@ -265,7 +264,7 @@ void main() { ...@@ -265,7 +264,7 @@ void main() {
expect(textStyle.color, isNot(Colors.orange)); expect(textStyle.color, isNot(Colors.orange));
textStyle = tester.widget<DefaultTextStyle>(find.descendant( textStyle = tester.widget<DefaultTextStyle>(find.descendant(
of: find.widgetWithText(RawMaterialButton, 'Second child'), of: find.widgetWithText(TextButton, 'Second child'),
matching: find.byType(DefaultTextStyle), matching: find.byType(DefaultTextStyle),
)).style; )).style;
expect(textStyle.textBaseline, TextBaseline.ideographic); expect(textStyle.textBaseline, TextBaseline.ideographic);
...@@ -290,13 +289,13 @@ void main() { ...@@ -290,13 +289,13 @@ void main() {
), ),
); );
final Rect firstRect = tester.getRect(find.byType(RawMaterialButton).at(0)); final Rect firstRect = tester.getRect(find.byType(TextButton).at(0));
expect(firstRect.width, 48.0); expect(firstRect.width, 48.0);
expect(firstRect.height, 48.0); expect(firstRect.height, 48.0);
final Rect secondRect = tester.getRect(find.byType(RawMaterialButton).at(1)); final Rect secondRect = tester.getRect(find.byType(TextButton).at(1));
expect(secondRect.width, 48.0); expect(secondRect.width, 48.0);
expect(secondRect.height, 48.0); expect(secondRect.height, 48.0);
final Rect thirdRect = tester.getRect(find.byType(RawMaterialButton).at(2)); final Rect thirdRect = tester.getRect(find.byType(TextButton).at(2));
expect(thirdRect.width, 48.0); expect(thirdRect.width, 48.0);
expect(thirdRect.height, 48.0); expect(thirdRect.height, 48.0);
}); });
...@@ -307,6 +306,7 @@ void main() { ...@@ -307,6 +306,7 @@ void main() {
Material( Material(
child: boilerplate( child: boilerplate(
child: ToggleButtons( child: ToggleButtons(
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
constraints: const BoxConstraints( constraints: const BoxConstraints(
minWidth: 50.0, minWidth: 50.0,
minHeight: 60.0, minHeight: 60.0,
...@@ -323,13 +323,13 @@ void main() { ...@@ -323,13 +323,13 @@ void main() {
), ),
); );
Rect firstRect = tester.getRect(find.byType(RawMaterialButton).at(0)); Rect firstRect = tester.getRect(find.byType(TextButton).at(0));
expect(firstRect.width, 50.0); expect(firstRect.width, 50.0);
expect(firstRect.height, 60.0); expect(firstRect.height, 60.0);
Rect secondRect = tester.getRect(find.byType(RawMaterialButton).at(1)); Rect secondRect = tester.getRect(find.byType(TextButton).at(1));
expect(secondRect.width, 50.0); expect(secondRect.width, 50.0);
expect(secondRect.height, 60.0); expect(secondRect.height, 60.0);
Rect thirdRect = tester.getRect(find.byType(RawMaterialButton).at(2)); Rect thirdRect = tester.getRect(find.byType(TextButton).at(2));
expect(thirdRect.width, 50.0); expect(thirdRect.width, 50.0);
expect(thirdRect.height, 60.0); expect(thirdRect.height, 60.0);
...@@ -338,6 +338,7 @@ void main() { ...@@ -338,6 +338,7 @@ void main() {
Material( Material(
child: boilerplate( child: boilerplate(
child: ToggleButtons( child: ToggleButtons(
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
constraints: const BoxConstraints( constraints: const BoxConstraints(
maxWidth: 20.0, maxWidth: 20.0,
maxHeight: 10.0, maxHeight: 10.0,
...@@ -354,13 +355,13 @@ void main() { ...@@ -354,13 +355,13 @@ void main() {
), ),
); );
firstRect = tester.getRect(find.byType(RawMaterialButton).at(0)); firstRect = tester.getRect(find.byType(TextButton).at(0));
expect(firstRect.width, 20.0); expect(firstRect.width, 20.0);
expect(firstRect.height, 10.0); expect(firstRect.height, 10.0);
secondRect = tester.getRect(find.byType(RawMaterialButton).at(1)); secondRect = tester.getRect(find.byType(TextButton).at(1));
expect(secondRect.width, 20.0); expect(secondRect.width, 20.0);
expect(secondRect.height, 10.0); expect(secondRect.height, 10.0);
thirdRect = tester.getRect(find.byType(RawMaterialButton).at(2)); thirdRect = tester.getRect(find.byType(TextButton).at(2));
expect(thirdRect.width, 20.0); expect(thirdRect.width, 20.0);
expect(thirdRect.height, 10.0); expect(thirdRect.height, 10.0);
}); });
...@@ -370,13 +371,13 @@ void main() { ...@@ -370,13 +371,13 @@ void main() {
(WidgetTester tester) async { (WidgetTester tester) async {
TextStyle buttonTextStyle(String text) { TextStyle buttonTextStyle(String text) {
return tester.widget<DefaultTextStyle>(find.descendant( return tester.widget<DefaultTextStyle>(find.descendant(
of: find.widgetWithText(RawMaterialButton, text), of: find.widgetWithText(TextButton, text),
matching: find.byType(DefaultTextStyle), matching: find.byType(DefaultTextStyle),
)).style; )).style;
} }
IconTheme iconTheme(IconData icon) { IconTheme iconTheme(IconData icon) {
return tester.widget(find.descendant( return tester.widget(find.descendant(
of: find.widgetWithIcon(RawMaterialButton, icon), of: find.widgetWithIcon(TextButton, icon),
matching: find.byType(IconTheme), matching: find.byType(IconTheme),
)); ));
} }
...@@ -468,13 +469,13 @@ void main() { ...@@ -468,13 +469,13 @@ void main() {
(WidgetTester tester) async { (WidgetTester tester) async {
TextStyle buttonTextStyle(String text) { TextStyle buttonTextStyle(String text) {
return tester.widget<DefaultTextStyle>(find.descendant( return tester.widget<DefaultTextStyle>(find.descendant(
of: find.widgetWithText(RawMaterialButton, text), of: find.widgetWithText(TextButton, text),
matching: find.byType(DefaultTextStyle), matching: find.byType(DefaultTextStyle),
)).style; )).style;
} }
IconTheme iconTheme(IconData icon) { IconTheme iconTheme(IconData icon) {
return tester.widget(find.descendant( return tester.widget(find.descendant(
of: find.widgetWithIcon(RawMaterialButton, icon), of: find.widgetWithIcon(TextButton, icon),
matching: find.byType(IconTheme), matching: find.byType(IconTheme),
)); ));
} }
...@@ -574,7 +575,7 @@ void main() { ...@@ -574,7 +575,7 @@ void main() {
); );
final Material material = tester.widget<Material>(find.descendant( final Material material = tester.widget<Material>(find.descendant(
of: find.byType(RawMaterialButton), of: find.byType(TextButton),
matching: find.byType(Material), matching: find.byType(Material),
)); ));
expect( expect(
...@@ -603,7 +604,7 @@ void main() { ...@@ -603,7 +604,7 @@ void main() {
); );
final Material material = tester.widget<Material>(find.descendant( final Material material = tester.widget<Material>(find.descendant(
of: find.byType(RawMaterialButton), of: find.byType(TextButton),
matching: find.byType(Material), matching: find.byType(Material),
)); ));
expect( expect(
...@@ -631,7 +632,7 @@ void main() { ...@@ -631,7 +632,7 @@ void main() {
); );
final Material material = tester.widget<Material>(find.descendant( final Material material = tester.widget<Material>(find.descendant(
of: find.byType(RawMaterialButton), of: find.byType(TextButton),
matching: find.byType(Material), matching: find.byType(Material),
)); ));
expect( expect(
...@@ -661,7 +662,7 @@ void main() { ...@@ -661,7 +662,7 @@ void main() {
); );
final Material material = tester.widget<Material>(find.descendant( final Material material = tester.widget<Material>(find.descendant(
of: find.byType(RawMaterialButton), of: find.byType(TextButton),
matching: find.byType(Material), matching: find.byType(Material),
)); ));
expect(material.color, customFillColor); expect(material.color, customFillColor);
...@@ -672,7 +673,7 @@ void main() { ...@@ -672,7 +673,7 @@ void main() {
Material buttonColor(String text) { Material buttonColor(String text) {
return tester.widget<Material>( return tester.widget<Material>(
find.descendant( find.descendant(
of: find.byType(RawMaterialButton), of: find.byType(TextButton),
matching: find.widgetWithText(Material, text), matching: find.widgetWithText(Material, text),
), ),
); );
...@@ -727,7 +728,7 @@ void main() { ...@@ -727,7 +728,7 @@ void main() {
Material buttonColor(String text) { Material buttonColor(String text) {
return tester.widget<Material>( return tester.widget<Material>(
find.descendant( find.descendant(
of: find.byType(RawMaterialButton), of: find.byType(TextButton),
matching: find.widgetWithText(Material, text), matching: find.widgetWithText(Material, text),
), ),
); );
...@@ -1615,7 +1616,7 @@ void main() { ...@@ -1615,7 +1616,7 @@ void main() {
final Key key1 = UniqueKey(); final Key key1 = UniqueKey();
await tester.pumpWidget(buildFrame(MaterialTapTargetSize.padded, key1)); await tester.pumpWidget(buildFrame(MaterialTapTargetSize.padded, key1));
expect(tester.getSize(find.byKey(key1)), const Size(228.0, 48.0)); expect(tester.getSize(find.byKey(key1)), const Size(228.0, 50.0));
final Key key2 = UniqueKey(); final Key key2 = UniqueKey();
await tester.pumpWidget(buildFrame(MaterialTapTargetSize.shrinkWrap, key2)); await tester.pumpWidget(buildFrame(MaterialTapTargetSize.shrinkWrap, key2));
...@@ -1644,7 +1645,7 @@ void main() { ...@@ -1644,7 +1645,7 @@ void main() {
final Key key1 = UniqueKey(); final Key key1 = UniqueKey();
await tester.pumpWidget(buildFrame(MaterialTapTargetSize.padded, key1)); await tester.pumpWidget(buildFrame(MaterialTapTargetSize.padded, key1));
expect(tester.getSize(find.byKey(key1)), const Size(228.0, 48.0)); expect(tester.getSize(find.byKey(key1)), const Size(228.0, 50.0));
final Key key2 = UniqueKey(); final Key key2 = UniqueKey();
await tester.pumpWidget(buildFrame(MaterialTapTargetSize.shrinkWrap, key2)); await tester.pumpWidget(buildFrame(MaterialTapTargetSize.shrinkWrap, key2));
...@@ -1674,7 +1675,7 @@ void main() { ...@@ -1674,7 +1675,7 @@ void main() {
final Key key1 = UniqueKey(); final Key key1 = UniqueKey();
await tester.pumpWidget(buildFrame(MaterialTapTargetSize.padded, key1)); await tester.pumpWidget(buildFrame(MaterialTapTargetSize.padded, key1));
expect(tester.getSize(find.byKey(key1)), const Size(48.0, 100.0)); expect(tester.getSize(find.byKey(key1)), const Size(50.0, 148.0));
final Key key2 = UniqueKey(); final Key key2 = UniqueKey();
await tester.pumpWidget(buildFrame(MaterialTapTargetSize.shrinkWrap, key2)); await tester.pumpWidget(buildFrame(MaterialTapTargetSize.shrinkWrap, key2));
...@@ -1910,4 +1911,31 @@ void main() { ...@@ -1910,4 +1911,31 @@ void main() {
await hoverGesture.removePointer(); await hoverGesture.removePointer();
}); });
testWidgets('Toggle buttons height matches MaterialTapTargetSize.padded height', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/97302
await tester.pumpWidget(
Material(
child: boilerplate(
child: ToggleButtons(
tapTargetSize: MaterialTapTargetSize.padded,
isSelected: const <bool>[false, false, false],
onPressed: (int index) {},
children: const <Widget>[
Icon(Icons.check),
Icon(Icons.access_alarm),
Icon(Icons.cake),
],
),
),
),
);
final Rect firstRect = tester.getRect(find.byType(TextButton).at(0));
expect(firstRect.height, 48.0);
final Rect secondRect = tester.getRect(find.byType(TextButton).at(1));
expect(secondRect.height, 48.0);
final Rect thirdRect = tester.getRect(find.byType(TextButton).at(2));
expect(thirdRect.height, 48.0);
});
} }
...@@ -142,15 +142,15 @@ void main() { ...@@ -142,15 +142,15 @@ void main() {
TextStyle textStyle; TextStyle textStyle;
textStyle = tester.widget<DefaultTextStyle>(find.descendant( textStyle = tester.widget<DefaultTextStyle>(find.descendant(
of: find.widgetWithText(RawMaterialButton, 'First child'), of: find.widgetWithText(TextButton, 'First child'),
matching: find.byType(DefaultTextStyle), matching: find.byType(DefaultTextStyle),
)).style; )).style;
expect(textStyle.textBaseline, TextBaseline.ideographic); expect(textStyle.textBaseline, TextBaseline.ideographic);
expect(textStyle.fontSize, 20.0); expect(textStyle.fontSize, 20.0);
expect(textStyle.color, isNot(Colors.orange)); expect(textStyle.color, isNot(Colors.orange));
textStyle = tester.widget<DefaultTextStyle>(find.descendant( textStyle = tester.widget<DefaultTextStyle>(find.descendant(
of: find.widgetWithText(RawMaterialButton, 'Second child'), of: find.widgetWithText(TextButton, 'Second child'),
matching: find.byType(DefaultTextStyle), matching: find.byType(DefaultTextStyle),
)).style; )).style;
expect(textStyle.textBaseline, TextBaseline.ideographic); expect(textStyle.textBaseline, TextBaseline.ideographic);
...@@ -171,6 +171,7 @@ void main() { ...@@ -171,6 +171,7 @@ void main() {
), ),
), ),
child: ToggleButtons( child: ToggleButtons(
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
isSelected: const <bool>[false, false, false], isSelected: const <bool>[false, false, false],
onPressed: (int index) {}, onPressed: (int index) {},
children: const <Widget>[ children: const <Widget>[
...@@ -184,13 +185,13 @@ void main() { ...@@ -184,13 +185,13 @@ void main() {
), ),
); );
Rect firstRect = tester.getRect(find.byType(RawMaterialButton).at(0)); Rect firstRect = tester.getRect(find.byType(TextButton).at(0));
expect(firstRect.width, 50.0); expect(firstRect.width, 50.0);
expect(firstRect.height, 60.0); expect(firstRect.height, 60.0);
Rect secondRect = tester.getRect(find.byType(RawMaterialButton).at(1)); Rect secondRect = tester.getRect(find.byType(TextButton).at(1));
expect(secondRect.width, 50.0); expect(secondRect.width, 50.0);
expect(secondRect.height, 60.0); expect(secondRect.height, 60.0);
Rect thirdRect = tester.getRect(find.byType(RawMaterialButton).at(2)); Rect thirdRect = tester.getRect(find.byType(TextButton).at(2));
expect(thirdRect.width, 50.0); expect(thirdRect.width, 50.0);
expect(thirdRect.height, 60.0); expect(thirdRect.height, 60.0);
...@@ -206,6 +207,7 @@ void main() { ...@@ -206,6 +207,7 @@ void main() {
), ),
), ),
child: ToggleButtons( child: ToggleButtons(
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
isSelected: const <bool>[false, false, false], isSelected: const <bool>[false, false, false],
onPressed: (int index) {}, onPressed: (int index) {},
children: const <Widget>[ children: const <Widget>[
...@@ -219,13 +221,13 @@ void main() { ...@@ -219,13 +221,13 @@ void main() {
), ),
); );
firstRect = tester.getRect(find.byType(RawMaterialButton).at(0)); firstRect = tester.getRect(find.byType(TextButton).at(0));
expect(firstRect.width, 20.0); expect(firstRect.width, 20.0);
expect(firstRect.height, 10.0); expect(firstRect.height, 10.0);
secondRect = tester.getRect(find.byType(RawMaterialButton).at(1)); secondRect = tester.getRect(find.byType(TextButton).at(1));
expect(secondRect.width, 20.0); expect(secondRect.width, 20.0);
expect(secondRect.height, 10.0); expect(secondRect.height, 10.0);
thirdRect = tester.getRect(find.byType(RawMaterialButton).at(2)); thirdRect = tester.getRect(find.byType(TextButton).at(2));
expect(thirdRect.width, 20.0); expect(thirdRect.width, 20.0);
expect(thirdRect.height, 10.0); expect(thirdRect.height, 10.0);
}); });
...@@ -235,13 +237,13 @@ void main() { ...@@ -235,13 +237,13 @@ void main() {
(WidgetTester tester) async { (WidgetTester tester) async {
TextStyle buttonTextStyle(String text) { TextStyle buttonTextStyle(String text) {
return tester.widget<DefaultTextStyle>(find.descendant( return tester.widget<DefaultTextStyle>(find.descendant(
of: find.widgetWithText(RawMaterialButton, text), of: find.widgetWithText(TextButton, text),
matching: find.byType(DefaultTextStyle), matching: find.byType(DefaultTextStyle),
)).style; )).style;
} }
IconTheme iconTheme(IconData icon) { IconTheme iconTheme(IconData icon) {
return tester.widget(find.descendant( return tester.widget(find.descendant(
of: find.widgetWithIcon(RawMaterialButton, icon), of: find.widgetWithIcon(TextButton, icon),
matching: find.byType(IconTheme), matching: find.byType(IconTheme),
)); ));
} }
...@@ -356,7 +358,7 @@ void main() { ...@@ -356,7 +358,7 @@ void main() {
); );
final Material material = tester.widget<Material>(find.descendant( final Material material = tester.widget<Material>(find.descendant(
of: find.byType(RawMaterialButton), of: find.byType(TextButton),
matching: find.byType(Material), matching: find.byType(Material),
)); ));
expect(material.color, customFillColor); expect(material.color, customFillColor);
...@@ -367,7 +369,7 @@ void main() { ...@@ -367,7 +369,7 @@ void main() {
Material buttonColor(String text) { Material buttonColor(String text) {
return tester.widget<Material>( return tester.widget<Material>(
find.descendant( find.descendant(
of: find.byType(RawMaterialButton), of: find.byType(TextButton),
matching: find.widgetWithText(Material, text), matching: find.widgetWithText(Material, text),
), ),
); );
...@@ -476,7 +478,6 @@ void main() { ...@@ -476,7 +478,6 @@ void main() {
inkFeatures, inkFeatures,
paints paints
..circle(color: splashColor) ..circle(color: splashColor)
..rect(color: highlightColor),
); );
await touchGesture.up(); await touchGesture.up();
...@@ -507,7 +508,6 @@ void main() { ...@@ -507,7 +508,6 @@ void main() {
await hoverGesture.removePointer(); await hoverGesture.removePointer();
}); });
testWidgets( testWidgets(
'Theme border width and border colors for enabled, selected and disabled states', 'Theme border width and border colors for enabled, selected and disabled states',
(WidgetTester tester) async { (WidgetTester tester) async {
......
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