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

[reland] Refactor ToggleButtons (remove RawMaterialButton) (#101760)

parent 3f2cb241
......@@ -8,11 +8,12 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
import 'button.dart';
import 'button_style.dart';
import 'color_scheme.dart';
import 'constants.dart';
import 'debug.dart';
import 'ink_ripple.dart';
import 'material_state.dart';
import 'text_button.dart';
import 'theme.dart';
import 'theme_data.dart';
import 'toggle_buttons_theme.dart';
......@@ -667,45 +668,129 @@ class ToggleButtons extends StatelessWidget {
final BorderSide borderSide = _getBorderSide(index, theme, toggleButtonsTheme);
final BorderSide trailingBorderSide = _getTrailingBorderSide(index, theme, toggleButtonsTheme);
return _ToggleButton(
selected: isSelected[index],
textStyle: textStyle,
constraints: constraints,
color: color,
selectedColor: selectedColor,
disabledColor: disabledColor,
fillColor: fillColor,
focusColor: focusColor ?? toggleButtonsTheme.focusColor,
highlightColor: highlightColor ?? toggleButtonsTheme.highlightColor,
hoverColor: hoverColor ?? toggleButtonsTheme.hoverColor,
splashColor: splashColor ?? toggleButtonsTheme.splashColor,
focusNode: focusNodes != null ? focusNodes![index] : null,
onPressed: onPressed != null
? () {onPressed!(index);}
: null,
mouseCursor: mouseCursor,
final Set<MaterialState> states = <MaterialState>{
if (isSelected[index] && onPressed != null) MaterialState.selected,
if (onPressed == null) MaterialState.disabled,
};
final Color effectiveFillColor = _ResolveFillColor(fillColor
?? toggleButtonsTheme.fillColor).resolve(states)
?? _DefaultFillColor(theme.colorScheme).resolve(states);
final Color currentColor;
if (onPressed != null && isSelected[index]) {
currentColor = selectedColor
?? toggleButtonsTheme.selectedColor
?? theme.colorScheme.primary;
} else if (onPressed != null && !isSelected[index]) {
currentColor = color
?? toggleButtonsTheme.color
?? theme.colorScheme.onSurface.withOpacity(0.87);
} 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;
final Size minimumSize = currentConstraints == null
? const Size.square(kMinInteractiveDimension)
: Size(currentConstraints.minWidth, currentConstraints.minHeight);
final Size? maximumSize = currentConstraints == null
? null
: Size(currentConstraints.maxWidth, currentConstraints.maxHeight);
final Size minPaddingSize;
switch (tapTargetSize ?? theme.materialTapTargetSize) {
case MaterialTapTargetSize.padded:
if (direction == Axis.horizontal) {
minPaddingSize = const Size(
0.0,
kMinInteractiveDimension,
);
} else {
minPaddingSize = const Size(
kMinInteractiveDimension,
0.0,
);
}
assert(minPaddingSize.width >= 0.0);
assert(minPaddingSize.height >= 0.0);
break;
case MaterialTapTargetSize.shrinkWrap:
minPaddingSize = Size.zero;
break;
}
Widget button = _SelectToggleButton(
leadingBorderSide: leadingBorderSide,
borderSide: borderSide,
trailingBorderSide: trailingBorderSide,
borderRadius: edgeBorderRadius,
clipRadius: clipBorderRadius,
isFirstButton: index == 0,
isLastButton: index == children.length - 1,
direction: direction,
verticalDirection: verticalDirection,
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?>(minimumSize),
maximumSize: MaterialStateProperty.all<Size?>(maximumSize),
shape: MaterialStateProperty.all<OutlinedBorder>(const RoundedRectangleBorder()),
mouseCursor: MaterialStateProperty.all<MouseCursor?>(mouseCursor),
visualDensity: VisualDensity.standard,
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
animationDuration: kThemeChangeDuration,
enableFeedback: true,
alignment: Alignment.center,
splashFactory: InkRipple.splashFactory,
),
onPressed: onPressed != null
? () {onPressed!(index);}
: null,
child: children[index],
),
),
);
});
final Widget result = direction == Axis.horizontal
? IntrinsicHeight(
child: Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: buttons,
if (currentConstraints != null) {
button = Center(child: button);
}
return MergeSemantics(
child: Semantics(
container: true,
enabled: onPressed != null,
child: _InputPadding(
minSize: minPaddingSize,
direction: direction,
child: button,
),
),
)
: IntrinsicWidth(
);
});
if (direction == Axis.vertical) {
return IntrinsicWidth(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
......@@ -713,18 +798,15 @@ class ToggleButtons extends StatelessWidget {
children: buttons,
),
);
}
final MaterialTapTargetSize resolvedTapTargetSize = tapTargetSize ?? theme.materialTapTargetSize;
switch (resolvedTapTargetSize) {
case MaterialTapTargetSize.padded:
return _InputPadding(
minSize: const Size(kMinInteractiveDimension, kMinInteractiveDimension),
direction: direction,
child: result,
return IntrinsicHeight(
child: Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: buttons,
),
);
case MaterialTapTargetSize.shrinkWrap:
return result;
}
}
@override
......@@ -754,250 +836,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({
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,
});
/// 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
class _ResolveFillColor extends MaterialStateProperty<Color?> with Diagnosticable {
_ResolveFillColor(this.primary);
......@@ -1028,9 +866,70 @@ 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 {
const _SelectToggleButton({
super.key,
required Widget super.child,
required this.leadingBorderSide,
required this.borderSide,
......
......@@ -12,6 +12,7 @@ import 'package:flutter/rendering.dart';
import 'package:flutter_test/flutter_test.dart';
import '../rendering/mock_canvas.dart';
import '../widgets/semantics_tester.dart';
const double _defaultBorderWidth = 1.0;
......@@ -26,7 +27,7 @@ void main() {
testWidgets('Initial toggle state is reflected', (WidgetTester tester) async {
TextStyle buttonTextStyle(String text) {
return tester.widget<DefaultTextStyle>(find.descendant(
of: find.widgetWithText(RawMaterialButton, text),
of: find.widgetWithText(TextButton, text),
matching: find.byType(DefaultTextStyle),
)).style;
}
......@@ -61,11 +62,10 @@ void main() {
(WidgetTester tester) async {
TextStyle buttonTextStyle(String text) {
return tester.widget<DefaultTextStyle>(find.descendant(
of: find.widgetWithText(RawMaterialButton, text),
of: find.widgetWithText(TextButton, text),
matching: find.byType(DefaultTextStyle),
)).style;
}
final List<bool> isSelected = <bool>[false, true];
final ThemeData theme = ThemeData();
await tester.pumpWidget(
......@@ -123,7 +123,7 @@ void main() {
(WidgetTester tester) async {
TextStyle buttonTextStyle(String text) {
return tester.widget<DefaultTextStyle>(find.descendant(
of: find.widgetWithText(RawMaterialButton, text),
of: find.widgetWithText(TextButton, text),
matching: find.byType(DefaultTextStyle),
)).style;
}
......@@ -220,14 +220,14 @@ void main() {
TextStyle textStyle;
textStyle = tester.widget<DefaultTextStyle>(find.descendant(
of: find.widgetWithText(RawMaterialButton, 'First child'),
of: find.widgetWithText(TextButton, 'First child'),
matching: find.byType(DefaultTextStyle),
)).style;
expect(textStyle.fontFamily, theme.textTheme.bodyText2!.fontFamily);
expect(textStyle.decoration, theme.textTheme.bodyText2!.decoration);
textStyle = tester.widget<DefaultTextStyle>(find.descendant(
of: find.widgetWithText(RawMaterialButton, 'Second child'),
of: find.widgetWithText(TextButton, 'Second child'),
matching: find.byType(DefaultTextStyle),
)).style;
expect(textStyle.fontFamily, theme.textTheme.bodyText2!.fontFamily);
......@@ -257,7 +257,7 @@ void main() {
TextStyle textStyle;
textStyle = tester.widget<DefaultTextStyle>(find.descendant(
of: find.widgetWithText(RawMaterialButton, 'First child'),
of: find.widgetWithText(TextButton, 'First child'),
matching: find.byType(DefaultTextStyle),
)).style;
expect(textStyle.textBaseline, TextBaseline.ideographic);
......@@ -265,7 +265,7 @@ void main() {
expect(textStyle.color, isNot(Colors.orange));
textStyle = tester.widget<DefaultTextStyle>(find.descendant(
of: find.widgetWithText(RawMaterialButton, 'Second child'),
of: find.widgetWithText(TextButton, 'Second child'),
matching: find.byType(DefaultTextStyle),
)).style;
expect(textStyle.textBaseline, TextBaseline.ideographic);
......@@ -290,13 +290,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.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.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.height, 48.0);
});
......@@ -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.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.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.height, 60.0);
......@@ -338,6 +338,7 @@ void main() {
Material(
child: boilerplate(
child: ToggleButtons(
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
constraints: const BoxConstraints(
maxWidth: 20.0,
maxHeight: 10.0,
......@@ -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.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.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.height, 10.0);
});
......@@ -370,13 +371,13 @@ void main() {
(WidgetTester tester) async {
TextStyle buttonTextStyle(String text) {
return tester.widget<DefaultTextStyle>(find.descendant(
of: find.widgetWithText(RawMaterialButton, text),
of: find.widgetWithText(TextButton, text),
matching: find.byType(DefaultTextStyle),
)).style;
}
IconTheme iconTheme(IconData icon) {
return tester.widget(find.descendant(
of: find.widgetWithIcon(RawMaterialButton, icon),
of: find.widgetWithIcon(TextButton, icon),
matching: find.byType(IconTheme),
));
}
......@@ -468,13 +469,13 @@ void main() {
(WidgetTester tester) async {
TextStyle buttonTextStyle(String text) {
return tester.widget<DefaultTextStyle>(find.descendant(
of: find.widgetWithText(RawMaterialButton, text),
of: find.widgetWithText(TextButton, text),
matching: find.byType(DefaultTextStyle),
)).style;
}
IconTheme iconTheme(IconData icon) {
return tester.widget(find.descendant(
of: find.widgetWithIcon(RawMaterialButton, icon),
of: find.widgetWithIcon(TextButton, icon),
matching: find.byType(IconTheme),
));
}
......@@ -574,7 +575,7 @@ void main() {
);
final Material material = tester.widget<Material>(find.descendant(
of: find.byType(RawMaterialButton),
of: find.byType(TextButton),
matching: find.byType(Material),
));
expect(
......@@ -603,7 +604,7 @@ void main() {
);
final Material material = tester.widget<Material>(find.descendant(
of: find.byType(RawMaterialButton),
of: find.byType(TextButton),
matching: find.byType(Material),
));
expect(
......@@ -631,7 +632,7 @@ void main() {
);
final Material material = tester.widget<Material>(find.descendant(
of: find.byType(RawMaterialButton),
of: find.byType(TextButton),
matching: find.byType(Material),
));
expect(
......@@ -661,7 +662,7 @@ void main() {
);
final Material material = tester.widget<Material>(find.descendant(
of: find.byType(RawMaterialButton),
of: find.byType(TextButton),
matching: find.byType(Material),
));
expect(material.color, customFillColor);
......@@ -672,7 +673,7 @@ void main() {
Material buttonColor(String text) {
return tester.widget<Material>(
find.descendant(
of: find.byType(RawMaterialButton),
of: find.byType(TextButton),
matching: find.widgetWithText(Material, text),
),
);
......@@ -727,7 +728,7 @@ void main() {
Material buttonColor(String text) {
return tester.widget<Material>(
find.descendant(
of: find.byType(RawMaterialButton),
of: find.byType(TextButton),
matching: find.widgetWithText(Material, text),
),
);
......@@ -1936,4 +1937,115 @@ void main() {
await hoverGesture.removePointer();
});
testWidgets('Toggle buttons height matches MaterialTapTargetSize.padded height', (WidgetTester tester) async {
await tester.pumpWidget(
Material(
child: boilerplate(
child: ToggleButtons(
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);
});
testWidgets('Toggle buttons constraints size does not affect minimum input padding', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/97302
final SemanticsTester semantics = SemanticsTester(tester);
await tester.pumpWidget(
Material(
child: boilerplate(
child: ToggleButtons(
isSelected: const <bool>[false, false, false],
onPressed: (int index) {},
constraints: const BoxConstraints.tightFor(
width: 86,
height: 32,
),
children: const <Widget>[
Icon(Icons.check),
Icon(Icons.access_alarm),
Icon(Icons.cake),
],
),
),
),
);
// Button's height is constrained to `32.0`.
final Rect firstRect = tester.getRect(find.byType(TextButton).at(0));
expect(firstRect.height, 32.0);
final Rect secondRect = tester.getRect(find.byType(TextButton).at(1));
expect(secondRect.height, 32.0);
final Rect thirdRect = tester.getRect(find.byType(TextButton).at(2));
expect(thirdRect.height, 32.0);
// While button's height is constrained to `32.0`, semantic node height
// should remain `48.0`, matching `MaterialTapTargetSize.padded` height (default).
expect(
semantics,
hasSemantics(
TestSemantics.root(
children: <TestSemantics>[
TestSemantics(
flags: <SemanticsFlag>[
SemanticsFlag.isButton,
SemanticsFlag.isEnabled,
SemanticsFlag.hasEnabledState,
SemanticsFlag.isFocusable,
],
actions: <SemanticsAction>[
SemanticsAction.tap,
],
rect: const Rect.fromLTRB(0.0, 0.0, 87.0, 48.0),
),
TestSemantics(
flags: <SemanticsFlag>[
SemanticsFlag.isButton,
SemanticsFlag.isEnabled,
SemanticsFlag.hasEnabledState,
SemanticsFlag.isFocusable,
],
actions: <SemanticsAction>[
SemanticsAction.tap,
],
rect: const Rect.fromLTRB(0.0, 0.0, 88.0, 48.0)
),
TestSemantics(
flags: <SemanticsFlag>[
SemanticsFlag.isButton,
SemanticsFlag.isEnabled,
SemanticsFlag.hasEnabledState,
SemanticsFlag.isFocusable,
],
actions: <SemanticsAction>[
SemanticsAction.tap,
],
rect: const Rect.fromLTRB(0.0, 0.0, 88.0, 48.0),
),
],
),
ignoreId: true,
ignoreRect: true,
ignoreTransform: true,
),
);
semantics.dispose();
});
}
......@@ -142,7 +142,7 @@ void main() {
TextStyle textStyle;
textStyle = tester.widget<DefaultTextStyle>(find.descendant(
of: find.widgetWithText(RawMaterialButton, 'First child'),
of: find.widgetWithText(TextButton, 'First child'),
matching: find.byType(DefaultTextStyle),
)).style;
expect(textStyle.textBaseline, TextBaseline.ideographic);
......@@ -150,7 +150,7 @@ void main() {
expect(textStyle.color, isNot(Colors.orange));
textStyle = tester.widget<DefaultTextStyle>(find.descendant(
of: find.widgetWithText(RawMaterialButton, 'Second child'),
of: find.widgetWithText(TextButton, 'Second child'),
matching: find.byType(DefaultTextStyle),
)).style;
expect(textStyle.textBaseline, TextBaseline.ideographic);
......@@ -171,6 +171,7 @@ void main() {
),
),
child: ToggleButtons(
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
isSelected: const <bool>[false, false, false],
onPressed: (int index) {},
children: const <Widget>[
......@@ -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.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.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.height, 60.0);
......@@ -206,6 +207,7 @@ void main() {
),
),
child: ToggleButtons(
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
isSelected: const <bool>[false, false, false],
onPressed: (int index) {},
children: const <Widget>[
......@@ -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.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.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.height, 10.0);
});
......@@ -235,13 +237,13 @@ void main() {
(WidgetTester tester) async {
TextStyle buttonTextStyle(String text) {
return tester.widget<DefaultTextStyle>(find.descendant(
of: find.widgetWithText(RawMaterialButton, text),
of: find.widgetWithText(TextButton, text),
matching: find.byType(DefaultTextStyle),
)).style;
}
IconTheme iconTheme(IconData icon) {
return tester.widget(find.descendant(
of: find.widgetWithIcon(RawMaterialButton, icon),
of: find.widgetWithIcon(TextButton, icon),
matching: find.byType(IconTheme),
));
}
......@@ -356,7 +358,7 @@ void main() {
);
final Material material = tester.widget<Material>(find.descendant(
of: find.byType(RawMaterialButton),
of: find.byType(TextButton),
matching: find.byType(Material),
));
expect(material.color, customFillColor);
......@@ -367,7 +369,7 @@ void main() {
Material buttonColor(String text) {
return tester.widget<Material>(
find.descendant(
of: find.byType(RawMaterialButton),
of: find.byType(TextButton),
matching: find.widgetWithText(Material, text),
),
);
......@@ -476,7 +478,6 @@ void main() {
inkFeatures,
paints
..circle(color: splashColor)
..rect(color: highlightColor),
);
await touchGesture.up();
......@@ -507,7 +508,6 @@ void main() {
await hoverGesture.removePointer();
});
testWidgets(
'Theme border width and border colors for enabled, selected and disabled states',
(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