mirror of
https://github.com/flutter/flutter
synced 2024-10-13 11:42:54 +00:00
Add side property to Chips, and resolve it and the state of Chips to be MaterialState aware (#68596)
This commit is contained in:
parent
f03caeafa7
commit
92d9630eaf
|
@ -94,10 +94,39 @@ abstract class ChipAttributes {
|
|||
/// * [MaterialState.pressed].
|
||||
TextStyle? get labelStyle;
|
||||
|
||||
/// The [ShapeBorder] to draw around the chip.
|
||||
/// The color and weight of the chip's outline.
|
||||
///
|
||||
/// Defaults to the shape in the ambient [ChipThemeData].
|
||||
ShapeBorder? get shape;
|
||||
/// Defaults to the border side in the ambient [ChipThemeData]. If the theme
|
||||
/// border side resolves to null, the default is the border side of [shape].
|
||||
///
|
||||
/// This value is combined with [shape] to create a shape decorated with an
|
||||
/// outline. If it is a [MaterialStateBorderSide],
|
||||
/// [MaterialStateProperty.resolve] is used for the following
|
||||
/// [MaterialState]s:
|
||||
///
|
||||
/// * [MaterialState.disabled].
|
||||
/// * [MaterialState.selected].
|
||||
/// * [MaterialState.hovered].
|
||||
/// * [MaterialState.focused].
|
||||
/// * [MaterialState.pressed].
|
||||
BorderSide? get side;
|
||||
|
||||
/// The [OutlinedBorder] to draw around the chip.
|
||||
///
|
||||
/// Defaults to the shape in the ambient [ChipThemeData]. If the theme
|
||||
/// shape resolves to null, the default is [StadiumBorder].
|
||||
///
|
||||
/// This shape is combined with [side] to create a shape decorated with an
|
||||
/// outline. If it is a [MaterialStateOutlinedBorder],
|
||||
/// [MaterialStateProperty.resolve] is used for the following
|
||||
/// [MaterialState]s:
|
||||
///
|
||||
/// * [MaterialState.disabled].
|
||||
/// * [MaterialState.selected].
|
||||
/// * [MaterialState.hovered].
|
||||
/// * [MaterialState.focused].
|
||||
/// * [MaterialState.pressed].
|
||||
OutlinedBorder? get shape;
|
||||
|
||||
/// {@macro flutter.widgets.Clip}
|
||||
///
|
||||
|
@ -576,6 +605,7 @@ class Chip extends StatelessWidget implements ChipAttributes, DeletableChipAttri
|
|||
this.deleteIconColor,
|
||||
this.useDeleteButtonTooltip = true,
|
||||
this.deleteButtonTooltipMessage,
|
||||
this.side,
|
||||
this.shape,
|
||||
this.clipBehavior = Clip.none,
|
||||
this.focusNode,
|
||||
|
@ -602,7 +632,9 @@ class Chip extends StatelessWidget implements ChipAttributes, DeletableChipAttri
|
|||
@override
|
||||
final EdgeInsetsGeometry? labelPadding;
|
||||
@override
|
||||
final ShapeBorder? shape;
|
||||
final BorderSide? side;
|
||||
@override
|
||||
final OutlinedBorder? shape;
|
||||
@override
|
||||
final Clip clipBehavior;
|
||||
@override
|
||||
|
@ -646,6 +678,7 @@ class Chip extends StatelessWidget implements ChipAttributes, DeletableChipAttri
|
|||
useDeleteButtonTooltip: useDeleteButtonTooltip,
|
||||
deleteButtonTooltipMessage: deleteButtonTooltipMessage,
|
||||
tapEnabled: false,
|
||||
side: side,
|
||||
shape: shape,
|
||||
clipBehavior: clipBehavior,
|
||||
focusNode: focusNode,
|
||||
|
@ -742,6 +775,7 @@ class InputChip extends StatelessWidget
|
|||
this.disabledColor,
|
||||
this.selectedColor,
|
||||
this.tooltip,
|
||||
this.side,
|
||||
this.shape,
|
||||
this.clipBehavior = Clip.none,
|
||||
this.focusNode,
|
||||
|
@ -801,7 +835,9 @@ class InputChip extends StatelessWidget
|
|||
@override
|
||||
final String? tooltip;
|
||||
@override
|
||||
final ShapeBorder? shape;
|
||||
final BorderSide? side;
|
||||
@override
|
||||
final OutlinedBorder? shape;
|
||||
@override
|
||||
final Clip clipBehavior;
|
||||
@override
|
||||
|
@ -850,6 +886,7 @@ class InputChip extends StatelessWidget
|
|||
disabledColor: disabledColor,
|
||||
selectedColor: selectedColor,
|
||||
tooltip: tooltip,
|
||||
side: side,
|
||||
shape: shape,
|
||||
clipBehavior: clipBehavior,
|
||||
focusNode: focusNode,
|
||||
|
@ -945,6 +982,7 @@ class ChoiceChip extends StatelessWidget
|
|||
this.selectedColor,
|
||||
this.disabledColor,
|
||||
this.tooltip,
|
||||
this.side,
|
||||
this.shape,
|
||||
this.clipBehavior = Clip.none,
|
||||
this.focusNode,
|
||||
|
@ -986,7 +1024,9 @@ class ChoiceChip extends StatelessWidget
|
|||
@override
|
||||
final String? tooltip;
|
||||
@override
|
||||
final ShapeBorder? shape;
|
||||
final BorderSide? side;
|
||||
@override
|
||||
final OutlinedBorder? shape;
|
||||
@override
|
||||
final Clip clipBehavior;
|
||||
@override
|
||||
|
@ -1028,6 +1068,7 @@ class ChoiceChip extends StatelessWidget
|
|||
showCheckmark: false,
|
||||
onDeleted: null,
|
||||
tooltip: tooltip,
|
||||
side: side,
|
||||
shape: shape,
|
||||
clipBehavior: clipBehavior,
|
||||
focusNode: focusNode,
|
||||
|
@ -1156,6 +1197,7 @@ class FilterChip extends StatelessWidget
|
|||
this.disabledColor,
|
||||
this.selectedColor,
|
||||
this.tooltip,
|
||||
this.side,
|
||||
this.shape,
|
||||
this.clipBehavior = Clip.none,
|
||||
this.focusNode,
|
||||
|
@ -1199,7 +1241,9 @@ class FilterChip extends StatelessWidget
|
|||
@override
|
||||
final String? tooltip;
|
||||
@override
|
||||
final ShapeBorder? shape;
|
||||
final BorderSide? side;
|
||||
@override
|
||||
final OutlinedBorder? shape;
|
||||
@override
|
||||
final Clip clipBehavior;
|
||||
@override
|
||||
|
@ -1242,6 +1286,7 @@ class FilterChip extends StatelessWidget
|
|||
pressElevation: pressElevation,
|
||||
selected: selected,
|
||||
tooltip: tooltip,
|
||||
side: side,
|
||||
shape: shape,
|
||||
clipBehavior: clipBehavior,
|
||||
focusNode: focusNode,
|
||||
|
@ -1325,6 +1370,7 @@ class ActionChip extends StatelessWidget implements ChipAttributes, TappableChip
|
|||
required this.onPressed,
|
||||
this.pressElevation,
|
||||
this.tooltip,
|
||||
this.side,
|
||||
this.shape,
|
||||
this.clipBehavior = Clip.none,
|
||||
this.focusNode,
|
||||
|
@ -1362,7 +1408,9 @@ class ActionChip extends StatelessWidget implements ChipAttributes, TappableChip
|
|||
@override
|
||||
final String? tooltip;
|
||||
@override
|
||||
final ShapeBorder? shape;
|
||||
final BorderSide? side;
|
||||
@override
|
||||
final OutlinedBorder? shape;
|
||||
@override
|
||||
final Clip clipBehavior;
|
||||
@override
|
||||
|
@ -1393,6 +1441,7 @@ class ActionChip extends StatelessWidget implements ChipAttributes, TappableChip
|
|||
tooltip: tooltip,
|
||||
labelStyle: labelStyle,
|
||||
backgroundColor: backgroundColor,
|
||||
side: side,
|
||||
shape: shape,
|
||||
clipBehavior: clipBehavior,
|
||||
focusNode: focusNode,
|
||||
|
@ -1477,6 +1526,7 @@ class RawChip extends StatefulWidget
|
|||
this.disabledColor,
|
||||
this.selectedColor,
|
||||
this.tooltip,
|
||||
this.side,
|
||||
this.shape,
|
||||
this.clipBehavior = Clip.none,
|
||||
this.focusNode,
|
||||
|
@ -1535,7 +1585,9 @@ class RawChip extends StatefulWidget
|
|||
@override
|
||||
final String? tooltip;
|
||||
@override
|
||||
final ShapeBorder? shape;
|
||||
final BorderSide? side;
|
||||
@override
|
||||
final OutlinedBorder? shape;
|
||||
@override
|
||||
final Clip clipBehavior;
|
||||
@override
|
||||
|
@ -1731,6 +1783,15 @@ class _RawChipState extends State<RawChip> with TickerProviderStateMixin<RawChip
|
|||
});
|
||||
}
|
||||
|
||||
OutlinedBorder _getShape(ChipThemeData theme) {
|
||||
final BorderSide? resolvedSide = MaterialStateProperty.resolveAs<BorderSide?>(widget.side, _states)
|
||||
?? MaterialStateProperty.resolveAs<BorderSide?>(theme.side, _states);
|
||||
final OutlinedBorder resolvedShape = MaterialStateProperty.resolveAs<OutlinedBorder?>(widget.shape, _states)
|
||||
?? MaterialStateProperty.resolveAs<OutlinedBorder?>(theme.shape, _states)
|
||||
?? const StadiumBorder();
|
||||
return resolvedShape.copyWith(side: resolvedSide);
|
||||
}
|
||||
|
||||
/// Picks between three different colors, depending upon the state of two
|
||||
/// different animations.
|
||||
Color? getBackgroundColor(ChipThemeData theme) {
|
||||
|
@ -1860,7 +1921,7 @@ class _RawChipState extends State<RawChip> with TickerProviderStateMixin<RawChip
|
|||
final ThemeData theme = Theme.of(context)!;
|
||||
final ChipThemeData chipTheme = ChipTheme.of(context);
|
||||
final TextDirection? textDirection = Directionality.maybeOf(context);
|
||||
final ShapeBorder shape = widget.shape ?? chipTheme.shape;
|
||||
final OutlinedBorder resolvedShape = _getShape(chipTheme);
|
||||
final double elevation = widget.elevation ?? chipTheme.elevation ?? _defaultElevation;
|
||||
final double pressElevation = widget.pressElevation ?? chipTheme.pressElevation ?? _defaultPressElevation;
|
||||
final Color shadowColor = widget.shadowColor ?? chipTheme.shadowColor ?? _defaultShadowColor;
|
||||
|
@ -1869,7 +1930,7 @@ class _RawChipState extends State<RawChip> with TickerProviderStateMixin<RawChip
|
|||
final bool showCheckmark = widget.showCheckmark ?? chipTheme.showCheckmark ?? true;
|
||||
|
||||
final TextStyle effectiveLabelStyle = widget.labelStyle ?? chipTheme.labelStyle;
|
||||
final Color? resolvedLabelColor = MaterialStateProperty.resolveAs<Color?>(effectiveLabelStyle.color, _states);
|
||||
final Color? resolvedLabelColor = MaterialStateProperty.resolveAs<Color?>(effectiveLabelStyle.color, _states);
|
||||
final TextStyle resolvedLabelStyle = effectiveLabelStyle.copyWith(color: resolvedLabelColor);
|
||||
final EdgeInsetsGeometry labelPadding = widget.labelPadding ?? chipTheme.labelPadding ?? _defaultLabelPadding;
|
||||
|
||||
|
@ -1877,7 +1938,7 @@ class _RawChipState extends State<RawChip> with TickerProviderStateMixin<RawChip
|
|||
elevation: isTapping ? pressElevation : elevation,
|
||||
shadowColor: widget.selected ? selectedShadowColor : shadowColor,
|
||||
animationDuration: pressedAnimationDuration,
|
||||
shape: shape,
|
||||
shape: resolvedShape,
|
||||
clipBehavior: widget.clipBehavior,
|
||||
child: InkWell(
|
||||
onFocusChange: _handleFocus,
|
||||
|
@ -1893,13 +1954,13 @@ class _RawChipState extends State<RawChip> with TickerProviderStateMixin<RawChip
|
|||
context,
|
||||
deleteIconKey,
|
||||
),
|
||||
customBorder: shape,
|
||||
customBorder: resolvedShape,
|
||||
child: AnimatedBuilder(
|
||||
animation: Listenable.merge(<Listenable>[selectController, enableController]),
|
||||
builder: (BuildContext context, Widget? child) {
|
||||
return Container(
|
||||
decoration: ShapeDecoration(
|
||||
shape: shape,
|
||||
shape: resolvedShape,
|
||||
color: getBackgroundColor(chipTheme),
|
||||
),
|
||||
child: child,
|
||||
|
|
|
@ -187,7 +187,8 @@ class ChipThemeData with Diagnosticable {
|
|||
this.checkmarkColor,
|
||||
this.labelPadding,
|
||||
required this.padding,
|
||||
required this.shape,
|
||||
this.side,
|
||||
this.shape,
|
||||
required this.labelStyle,
|
||||
required this.secondaryLabelStyle,
|
||||
required this.brightness,
|
||||
|
@ -198,7 +199,6 @@ class ChipThemeData with Diagnosticable {
|
|||
assert(selectedColor != null),
|
||||
assert(secondarySelectedColor != null),
|
||||
assert(padding != null),
|
||||
assert(shape != null),
|
||||
assert(labelStyle != null),
|
||||
assert(secondaryLabelStyle != null),
|
||||
assert(brightness != null);
|
||||
|
@ -244,7 +244,6 @@ class ChipThemeData with Diagnosticable {
|
|||
const int disabledAlpha = 0x0c; // 38% * 12% = 5%
|
||||
const int selectAlpha = 0x3d; // 12% + 12% = 24%
|
||||
const int textLabelAlpha = 0xde; // 87%
|
||||
const ShapeBorder shape = StadiumBorder();
|
||||
const EdgeInsetsGeometry padding = EdgeInsets.all(4.0);
|
||||
|
||||
primaryColor = primaryColor ?? (brightness == Brightness.light ? Colors.black : Colors.white);
|
||||
|
@ -265,7 +264,6 @@ class ChipThemeData with Diagnosticable {
|
|||
selectedColor: selectedColor,
|
||||
secondarySelectedColor: secondarySelectedColor,
|
||||
padding: padding,
|
||||
shape: shape,
|
||||
labelStyle: labelStyle,
|
||||
secondaryLabelStyle: secondaryLabelStyle,
|
||||
brightness: brightness!,
|
||||
|
@ -350,10 +348,37 @@ class ChipThemeData with Diagnosticable {
|
|||
/// Defaults to 4 logical pixels on all sides.
|
||||
final EdgeInsetsGeometry padding;
|
||||
|
||||
/// The color and weight of the chip's outline.
|
||||
///
|
||||
/// If null, the chip defaults to the border side of [shape].
|
||||
///
|
||||
/// This value is combined with [shape] to create a shape decorated with an
|
||||
/// outline. If it is a [MaterialStateBorderSide],
|
||||
/// [MaterialStateProperty.resolve] is used for the following
|
||||
/// [MaterialState]s:
|
||||
///
|
||||
/// * [MaterialState.disabled].
|
||||
/// * [MaterialState.selected].
|
||||
/// * [MaterialState.hovered].
|
||||
/// * [MaterialState.focused].
|
||||
/// * [MaterialState.pressed].
|
||||
final BorderSide? side;
|
||||
|
||||
/// The border to draw around the chip.
|
||||
///
|
||||
/// Defaults to a [StadiumBorder]. Must not be null.
|
||||
final ShapeBorder shape;
|
||||
/// If null, the chip defaults to a [StadiumBorder].
|
||||
///
|
||||
/// This shape is combined with [side] to create a shape decorated with an
|
||||
/// outline. If it is a [MaterialStateOutlinedBorder],
|
||||
/// [MaterialStateProperty.resolve] is used for the following
|
||||
/// [MaterialState]s:
|
||||
///
|
||||
/// * [MaterialState.disabled].
|
||||
/// * [MaterialState.selected].
|
||||
/// * [MaterialState.hovered].
|
||||
/// * [MaterialState.focused].
|
||||
/// * [MaterialState.pressed].
|
||||
final OutlinedBorder? shape;
|
||||
|
||||
/// The style to be applied to the chip's label.
|
||||
///
|
||||
|
@ -396,7 +421,8 @@ class ChipThemeData with Diagnosticable {
|
|||
Color? checkmarkColor,
|
||||
EdgeInsetsGeometry? labelPadding,
|
||||
EdgeInsetsGeometry? padding,
|
||||
ShapeBorder? shape,
|
||||
BorderSide? side,
|
||||
OutlinedBorder? shape,
|
||||
TextStyle? labelStyle,
|
||||
TextStyle? secondaryLabelStyle,
|
||||
Brightness? brightness,
|
||||
|
@ -414,6 +440,7 @@ class ChipThemeData with Diagnosticable {
|
|||
checkmarkColor: checkmarkColor ?? this.checkmarkColor,
|
||||
labelPadding: labelPadding ?? this.labelPadding,
|
||||
padding: padding ?? this.padding,
|
||||
side: side ?? this.side,
|
||||
shape: shape ?? this.shape,
|
||||
labelStyle: labelStyle ?? this.labelStyle,
|
||||
secondaryLabelStyle: secondaryLabelStyle ?? this.secondaryLabelStyle,
|
||||
|
@ -443,7 +470,8 @@ class ChipThemeData with Diagnosticable {
|
|||
checkmarkColor: Color.lerp(a?.checkmarkColor, b?.checkmarkColor, t),
|
||||
labelPadding: EdgeInsetsGeometry.lerp(a?.labelPadding, b?.labelPadding, t),
|
||||
padding: EdgeInsetsGeometry.lerp(a?.padding, b?.padding, t)!,
|
||||
shape: ShapeBorder.lerp(a?.shape, b?.shape, t)!,
|
||||
side: _lerpSides(a?.side, b?.side, t),
|
||||
shape: _lerpShapes(a?.shape, b?.shape, t),
|
||||
labelStyle: TextStyle.lerp(a?.labelStyle, b?.labelStyle, t)!,
|
||||
secondaryLabelStyle: TextStyle.lerp(a?.secondaryLabelStyle, b?.secondaryLabelStyle, t)!,
|
||||
brightness: t < 0.5 ? a?.brightness ?? Brightness.light : b?.brightness ?? Brightness.light,
|
||||
|
@ -452,6 +480,24 @@ class ChipThemeData with Diagnosticable {
|
|||
);
|
||||
}
|
||||
|
||||
// Special case because BorderSide.lerp() doesn't support null arguments.
|
||||
static BorderSide? _lerpSides(BorderSide? a, BorderSide? b, double t) {
|
||||
if (a == null && b == null)
|
||||
return null;
|
||||
if (a == null)
|
||||
return BorderSide.lerp(BorderSide(width: 0, color: b!.color.withAlpha(0)), b, t);
|
||||
if (b == null)
|
||||
return BorderSide.lerp(BorderSide(width: 0, color: a.color.withAlpha(0)), a, t);
|
||||
return BorderSide.lerp(a, b, t);
|
||||
}
|
||||
|
||||
// TODO(perclasson): OutlinedBorder needs a lerp method - https://github.com/flutter/flutter/issues/60555.
|
||||
static OutlinedBorder? _lerpShapes(OutlinedBorder? a, OutlinedBorder? b, double t) {
|
||||
if (a == null && b == null)
|
||||
return null;
|
||||
return ShapeBorder.lerp(a, b, t) as OutlinedBorder?;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
return hashValues(
|
||||
|
@ -465,6 +511,7 @@ class ChipThemeData with Diagnosticable {
|
|||
checkmarkColor,
|
||||
labelPadding,
|
||||
padding,
|
||||
side,
|
||||
shape,
|
||||
labelStyle,
|
||||
secondaryLabelStyle,
|
||||
|
@ -493,6 +540,7 @@ class ChipThemeData with Diagnosticable {
|
|||
&& other.checkmarkColor == checkmarkColor
|
||||
&& other.labelPadding == labelPadding
|
||||
&& other.padding == padding
|
||||
&& other.side == side
|
||||
&& other.shape == shape
|
||||
&& other.labelStyle == labelStyle
|
||||
&& other.secondaryLabelStyle == secondaryLabelStyle
|
||||
|
@ -520,6 +568,7 @@ class ChipThemeData with Diagnosticable {
|
|||
properties.add(ColorProperty('checkMarkColor', checkmarkColor, defaultValue: defaultData.checkmarkColor));
|
||||
properties.add(DiagnosticsProperty<EdgeInsetsGeometry>('labelPadding', labelPadding, defaultValue: defaultData.labelPadding));
|
||||
properties.add(DiagnosticsProperty<EdgeInsetsGeometry>('padding', padding, defaultValue: defaultData.padding));
|
||||
properties.add(DiagnosticsProperty<BorderSide>('side', side, defaultValue: defaultData.side));
|
||||
properties.add(DiagnosticsProperty<ShapeBorder>('shape', shape, defaultValue: defaultData.shape));
|
||||
properties.add(DiagnosticsProperty<TextStyle>('labelStyle', labelStyle, defaultValue: defaultData.labelStyle));
|
||||
properties.add(DiagnosticsProperty<TextStyle>('secondaryLabelStyle', secondaryLabelStyle, defaultValue: defaultData.secondaryLabelStyle));
|
||||
|
|
|
@ -21,9 +21,15 @@ import 'package:flutter/rendering.dart';
|
|||
/// * [MaterialStateColor], a [Color] that implements `MaterialStateProperty`
|
||||
/// which is used in APIs that need to accept either a [Color] or a
|
||||
/// `MaterialStateProperty<Color>`.
|
||||
/// * [MaterialStateMouseCursor], a [MouseCursor] that implements `MaterialStateProperty`
|
||||
/// which is used in APIs that need to accept either a [MouseCursor] or a
|
||||
/// [MaterialStateProperty<MouseCursor>].
|
||||
/// * [MaterialStateMouseCursor], a [MouseCursor] that implements
|
||||
/// `MaterialStateProperty` which is used in APIs that need to accept either
|
||||
/// a [MouseCursor] or a [MaterialStateProperty<MouseCursor>].
|
||||
/// * [MaterialStateOutlinedBorder], an [OutlinedBorder] that implements
|
||||
/// `MaterialStateProperty` which is used in APIs that need to accept either
|
||||
/// an [OutlinedBorder] or a [MaterialStateProperty<OutlinedBorder>].
|
||||
/// * [MaterialStateBorderSide], a [BorderSide] that implements
|
||||
/// `MaterialStateProperty` which is used in APIs that need to accept either
|
||||
/// a [BorderSide] or a [MaterialStateProperty<BorderSide>].
|
||||
|
||||
enum MaterialState {
|
||||
/// The state when the user drags their mouse cursor over the given widget.
|
||||
|
@ -282,6 +288,123 @@ class _EnabledAndDisabledMouseCursor extends MaterialStateMouseCursor {
|
|||
String get debugDescription => 'MaterialStateMouseCursor($name)';
|
||||
}
|
||||
|
||||
/// Defines a [BorderSide] whose value depends on a set of [MaterialState]s
|
||||
/// which represent the interactive state of a component.
|
||||
///
|
||||
/// To use a [MaterialStateBorderSide], you should create a subclass of a
|
||||
/// [MaterialStateBorderSide] and override the abstract `resolve` method.
|
||||
///
|
||||
/// {@tool dartpad --template=stateful_widget_material}
|
||||
///
|
||||
/// This example defines a subclass of [MaterialStateBorderSide], that resolves
|
||||
/// to a red border side when its widget is selected.
|
||||
///
|
||||
/// ```dart preamble
|
||||
/// class RedSelectedBorderSide extends MaterialStateBorderSide {
|
||||
/// @override
|
||||
/// BorderSide resolve(Set<MaterialState> states) {
|
||||
/// if (states.contains(MaterialState.selected)) {
|
||||
/// return BorderSide(
|
||||
/// width: 1,
|
||||
/// color: Colors.red,
|
||||
/// );
|
||||
/// }
|
||||
/// return null; // Defer to default value on the theme or widget.
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// ```dart
|
||||
/// bool isSelected = true;
|
||||
///
|
||||
/// Widget build(BuildContext context) {
|
||||
/// return FilterChip(
|
||||
/// label: Text('Select chip'),
|
||||
/// selected: isSelected,
|
||||
/// onSelected: (bool value) {
|
||||
/// setState(() {
|
||||
/// isSelected = value;
|
||||
/// });
|
||||
/// },
|
||||
/// side: RedSelectedBorderSide(),
|
||||
/// );
|
||||
/// }
|
||||
/// ```
|
||||
/// {@end-tool}
|
||||
///
|
||||
/// This class should only be used for parameters which are documented to take
|
||||
/// [MaterialStateBorderSide], otherwise only the default state will be used.
|
||||
abstract class MaterialStateBorderSide extends BorderSide implements MaterialStateProperty<BorderSide?> {
|
||||
/// Creates a [MaterialStateBorderSide].
|
||||
const MaterialStateBorderSide();
|
||||
|
||||
/// Returns a [BorderSide] that's to be used when a Material component is
|
||||
/// in the specified state. Return null to defer to the default value of the
|
||||
/// widget or theme.
|
||||
@override
|
||||
BorderSide? resolve(Set<MaterialState> states);
|
||||
}
|
||||
|
||||
/// Defines an [OutlinedBorder] whose value depends on a set of [MaterialState]s
|
||||
/// which represent the interactive state of a component.
|
||||
///
|
||||
/// To use a [MaterialStateOutlinedBorder], you should create a subclass of an
|
||||
/// [OutlinedBorder] and implement [MaterialStateOutlinedBorder]'s abstract
|
||||
/// `resolve` method.
|
||||
///
|
||||
/// {@tool dartpad --template=stateful_widget_material}
|
||||
///
|
||||
/// This example defines a subclass of [RoundedRectangleBorder] and an
|
||||
/// implementation of [MaterialStateOutlinedBorder], that resolves to
|
||||
/// [RoundedRectangleBorder] when its widget is selected.
|
||||
///
|
||||
/// ```dart preamble
|
||||
/// class SelectedBorder extends RoundedRectangleBorder implements MaterialStateOutlinedBorder {
|
||||
/// @override
|
||||
/// OutlinedBorder resolve(Set<MaterialState> states) {
|
||||
/// if (states.contains(MaterialState.selected)) {
|
||||
/// return RoundedRectangleBorder();
|
||||
/// }
|
||||
/// return null; // Defer to default value on the theme or widget.
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// ```dart
|
||||
/// bool isSelected = true;
|
||||
///
|
||||
/// Widget build(BuildContext context) {
|
||||
/// return FilterChip(
|
||||
/// label: Text('Select chip'),
|
||||
/// selected: isSelected,
|
||||
/// onSelected: (bool value) {
|
||||
/// setState(() {
|
||||
/// isSelected = value;
|
||||
/// });
|
||||
/// },
|
||||
/// shape: SelectedBorder(),
|
||||
/// );
|
||||
/// }
|
||||
/// ```
|
||||
/// {@end-tool}
|
||||
///
|
||||
/// This class should only be used for parameters which are documented to take
|
||||
/// [MaterialStateOutlinedBorder], otherwise only the default state will be used.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [ShapeBorder] the base class for shape outlines.
|
||||
abstract class MaterialStateOutlinedBorder extends OutlinedBorder implements MaterialStateProperty<OutlinedBorder?> {
|
||||
/// Creates a [MaterialStateOutlinedBorder].
|
||||
const MaterialStateOutlinedBorder();
|
||||
|
||||
/// Returns an [OutlinedBorder] that's to be used when a Material component is
|
||||
/// in the specified state. Return null to defer to the default value of the
|
||||
/// widget or theme.
|
||||
@override
|
||||
OutlinedBorder? resolve(Set<MaterialState> states);
|
||||
}
|
||||
|
||||
/// Interface for classes that [resolve] to a value of type `T` based
|
||||
/// on a widget's interactive "state", which is defined as a set
|
||||
/// of [MaterialState]s.
|
||||
|
|
|
@ -2382,6 +2382,216 @@ void main() {
|
|||
await gesture.removePointer();
|
||||
});
|
||||
|
||||
testWidgets('Chip uses stateful border side color in different states', (WidgetTester tester) async {
|
||||
final FocusNode focusNode = FocusNode();
|
||||
|
||||
const Color pressedColor = Color(0x00000001);
|
||||
const Color hoverColor = Color(0x00000002);
|
||||
const Color focusedColor = Color(0x00000003);
|
||||
const Color defaultColor = Color(0x00000004);
|
||||
const Color selectedColor = Color(0x00000005);
|
||||
const Color disabledColor = Color(0x00000006);
|
||||
|
||||
BorderSide getBorderSide(Set<MaterialState> states) {
|
||||
Color sideColor = defaultColor;
|
||||
|
||||
if (states.contains(MaterialState.disabled))
|
||||
sideColor = disabledColor;
|
||||
|
||||
else if (states.contains(MaterialState.pressed))
|
||||
sideColor = pressedColor;
|
||||
|
||||
else if (states.contains(MaterialState.hovered))
|
||||
sideColor = hoverColor;
|
||||
|
||||
else if (states.contains(MaterialState.focused))
|
||||
sideColor = focusedColor;
|
||||
|
||||
else if (states.contains(MaterialState.selected))
|
||||
sideColor = selectedColor;
|
||||
|
||||
return BorderSide(color: sideColor, width: 1);
|
||||
}
|
||||
|
||||
Widget chipWidget({ bool enabled = true, bool selected = false }) {
|
||||
return MaterialApp(
|
||||
home: Scaffold(
|
||||
body: Focus(
|
||||
focusNode: focusNode,
|
||||
child: ChoiceChip(
|
||||
label: const Text('Chip'),
|
||||
selected: selected,
|
||||
onSelected: enabled ? (_) {} : null,
|
||||
side: _MaterialStateBorderSide(getBorderSide),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Default, not disabled.
|
||||
await tester.pumpWidget(chipWidget());
|
||||
expect(find.byType(RawChip), paints..rrect(color: defaultColor));
|
||||
|
||||
// Selected.
|
||||
await tester.pumpWidget(chipWidget(selected: true));
|
||||
expect(find.byType(RawChip), paints..rrect(color: selectedColor));
|
||||
|
||||
// Focused.
|
||||
final FocusNode chipFocusNode = focusNode.children.first;
|
||||
chipFocusNode.requestFocus();
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.byType(RawChip), paints..rrect(color: focusedColor));
|
||||
|
||||
// Hovered.
|
||||
final Offset center = tester.getCenter(find.byType(ChoiceChip));
|
||||
final TestGesture gesture = await tester.createGesture(
|
||||
kind: PointerDeviceKind.mouse,
|
||||
);
|
||||
await gesture.addPointer();
|
||||
await gesture.moveTo(center);
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.byType(RawChip), paints..rrect(color: hoverColor));
|
||||
|
||||
// Pressed.
|
||||
await gesture.down(center);
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.byType(RawChip), paints..rrect(color: pressedColor));
|
||||
|
||||
// Disabled.
|
||||
await tester.pumpWidget(chipWidget(enabled: false));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.byType(RawChip), paints..rrect(color: disabledColor));
|
||||
|
||||
// Teardown.
|
||||
await gesture.removePointer();
|
||||
});
|
||||
|
||||
testWidgets('Chip uses stateful shape in different states', (WidgetTester tester) async {
|
||||
final FocusNode focusNode = FocusNode();
|
||||
OutlinedBorder? getShape(Set<MaterialState> states) {
|
||||
|
||||
if (states.contains(MaterialState.disabled))
|
||||
return const BeveledRectangleBorder();
|
||||
|
||||
else if (states.contains(MaterialState.pressed))
|
||||
return const CircleBorder();
|
||||
|
||||
else if (states.contains(MaterialState.hovered))
|
||||
return const ContinuousRectangleBorder();
|
||||
|
||||
else if (states.contains(MaterialState.focused))
|
||||
return const RoundedRectangleBorder();
|
||||
|
||||
else if (states.contains(MaterialState.selected))
|
||||
return const BeveledRectangleBorder();
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
Widget chipWidget({ bool enabled = true, bool selected = false }) {
|
||||
return MaterialApp(
|
||||
home: Scaffold(
|
||||
body: Focus(
|
||||
focusNode: focusNode,
|
||||
child: ChoiceChip(
|
||||
selected: selected,
|
||||
label: const Text('Chip'),
|
||||
shape: _MaterialStateOutlinedBorder(getShape),
|
||||
onSelected: enabled ? (_) {} : null,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Default, not disabled. Defers to default shape.
|
||||
await tester.pumpWidget(chipWidget());
|
||||
expect(getMaterial(tester).shape, isA<StadiumBorder>());
|
||||
|
||||
// Selected.
|
||||
await tester.pumpWidget(chipWidget(selected: true));
|
||||
expect(getMaterial(tester).shape, isA<BeveledRectangleBorder>());
|
||||
|
||||
// Focused.
|
||||
final FocusNode chipFocusNode = focusNode.children.first;
|
||||
chipFocusNode.requestFocus();
|
||||
await tester.pumpAndSettle();
|
||||
expect(getMaterial(tester).shape, isA<RoundedRectangleBorder>());
|
||||
|
||||
// Hovered.
|
||||
final Offset center = tester.getCenter(find.byType(ChoiceChip));
|
||||
final TestGesture gesture = await tester.createGesture(
|
||||
kind: PointerDeviceKind.mouse,
|
||||
);
|
||||
await gesture.addPointer();
|
||||
await gesture.moveTo(center);
|
||||
await tester.pumpAndSettle();
|
||||
expect(getMaterial(tester).shape, isA<ContinuousRectangleBorder>());
|
||||
|
||||
// Pressed.
|
||||
await gesture.down(center);
|
||||
await tester.pumpAndSettle();
|
||||
expect(getMaterial(tester).shape, isA<CircleBorder>());
|
||||
|
||||
// Disabled.
|
||||
await tester.pumpWidget(chipWidget(enabled: false));
|
||||
await tester.pumpAndSettle();
|
||||
expect(getMaterial(tester).shape, isA<BeveledRectangleBorder>());
|
||||
|
||||
// Teardown.
|
||||
await gesture.removePointer();
|
||||
});
|
||||
|
||||
testWidgets('Chip defers to theme, if shape and side resolves to null', (WidgetTester tester) async {
|
||||
const OutlinedBorder themeShape = StadiumBorder();
|
||||
const OutlinedBorder selectedShape = RoundedRectangleBorder();
|
||||
const BorderSide themeBorderSide = BorderSide(color: Color(0x00000001), width: 1);
|
||||
const BorderSide selectedBorderSide = BorderSide(color: Color(0x00000002), width: 1);
|
||||
|
||||
OutlinedBorder? getShape(Set<MaterialState> states) {
|
||||
if (states.contains(MaterialState.selected))
|
||||
return selectedShape;
|
||||
return null;
|
||||
}
|
||||
|
||||
BorderSide? getBorderSide(Set<MaterialState> states) {
|
||||
if (states.contains(MaterialState.selected))
|
||||
return selectedBorderSide;
|
||||
return null;
|
||||
}
|
||||
|
||||
Widget chipWidget({ bool enabled = true, bool selected = false }) {
|
||||
return MaterialApp(
|
||||
theme: ThemeData(
|
||||
chipTheme: ThemeData.light().chipTheme.copyWith(
|
||||
shape: themeShape,
|
||||
side: themeBorderSide,
|
||||
),
|
||||
),
|
||||
home: Scaffold(
|
||||
body: ChoiceChip(
|
||||
selected: selected,
|
||||
label: const Text('Chip'),
|
||||
shape: _MaterialStateOutlinedBorder(getShape),
|
||||
side: _MaterialStateBorderSide(getBorderSide),
|
||||
onSelected: enabled ? (_) {} : null,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Default, not disabled. Defer to theme.
|
||||
await tester.pumpWidget(chipWidget());
|
||||
expect(getMaterial(tester).shape, isA<StadiumBorder>());
|
||||
expect(find.byType(RawChip), paints..rrect(color: themeBorderSide.color));
|
||||
|
||||
// Selected.
|
||||
await tester.pumpWidget(chipWidget(selected: true));
|
||||
expect(getMaterial(tester).shape, isA<RoundedRectangleBorder>());
|
||||
expect(find.byType(RawChip), paints..drrect(color: selectedBorderSide.color));
|
||||
});
|
||||
|
||||
testWidgets('loses focus when disabled', (WidgetTester tester) async {
|
||||
final FocusNode focusNode = FocusNode(debugLabel: 'InputChip');
|
||||
await tester.pumpWidget(
|
||||
|
@ -2707,3 +2917,21 @@ void main() {
|
|||
await tapGesture.up();
|
||||
});
|
||||
}
|
||||
|
||||
class _MaterialStateOutlinedBorder extends StadiumBorder implements MaterialStateOutlinedBorder {
|
||||
const _MaterialStateOutlinedBorder(this.resolver);
|
||||
|
||||
final MaterialPropertyResolver<OutlinedBorder?> resolver;
|
||||
|
||||
@override
|
||||
OutlinedBorder? resolve(Set<MaterialState> states) => resolver(states);
|
||||
}
|
||||
|
||||
class _MaterialStateBorderSide extends MaterialStateBorderSide {
|
||||
const _MaterialStateBorderSide(this.resolver);
|
||||
|
||||
final MaterialPropertyResolver<BorderSide?> resolver;
|
||||
|
||||
@override
|
||||
BorderSide? resolve(Set<MaterialState> states) => resolver(states);
|
||||
}
|
||||
|
|
|
@ -184,7 +184,8 @@ void main() {
|
|||
expect(lightTheme.secondarySelectedColor, equals(customColor1.withAlpha(0x3d)));
|
||||
expect(lightTheme.labelPadding, isNull);
|
||||
expect(lightTheme.padding, equals(const EdgeInsets.all(4.0)));
|
||||
expect(lightTheme.shape, isA<StadiumBorder>());
|
||||
expect(lightTheme.side, isNull);
|
||||
expect(lightTheme.shape, isNull);
|
||||
expect(lightTheme.labelStyle.color, equals(Colors.black.withAlpha(0xde)));
|
||||
expect(lightTheme.secondaryLabelStyle.color, equals(customColor1.withAlpha(0xde)));
|
||||
expect(lightTheme.brightness, equals(Brightness.light));
|
||||
|
@ -202,7 +203,8 @@ void main() {
|
|||
expect(darkTheme.secondarySelectedColor, equals(customColor1.withAlpha(0x3d)));
|
||||
expect(darkTheme.labelPadding, isNull);
|
||||
expect(darkTheme.padding, equals(const EdgeInsets.all(4.0)));
|
||||
expect(darkTheme.shape, isA<StadiumBorder>());
|
||||
expect(darkTheme.side, isNull);
|
||||
expect(darkTheme.shape, isNull);
|
||||
expect(darkTheme.labelStyle.color, equals(Colors.white.withAlpha(0xde)));
|
||||
expect(darkTheme.secondaryLabelStyle.color, equals(customColor1.withAlpha(0xde)));
|
||||
expect(darkTheme.brightness, equals(Brightness.dark));
|
||||
|
@ -220,7 +222,8 @@ void main() {
|
|||
expect(customTheme.secondarySelectedColor, equals(customColor2.withAlpha(0x3d)));
|
||||
expect(customTheme.labelPadding, isNull);
|
||||
expect(customTheme.padding, equals(const EdgeInsets.all(4.0)));
|
||||
expect(customTheme.shape, isA<StadiumBorder>());
|
||||
expect(customTheme.side, isNull);
|
||||
expect(customTheme.shape, isNull);
|
||||
expect(customTheme.labelStyle.color, equals(customColor1.withAlpha(0xde)));
|
||||
expect(customTheme.secondaryLabelStyle.color, equals(customColor2.withAlpha(0xde)));
|
||||
expect(customTheme.brightness, equals(Brightness.light));
|
||||
|
@ -234,6 +237,8 @@ void main() {
|
|||
).copyWith(
|
||||
elevation: 1.0,
|
||||
labelPadding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||
shape: const StadiumBorder(),
|
||||
side: const BorderSide(color: Colors.black),
|
||||
pressElevation: 4.0,
|
||||
shadowColor: Colors.black,
|
||||
selectedShadowColor: Colors.black,
|
||||
|
@ -246,6 +251,8 @@ void main() {
|
|||
).copyWith(
|
||||
padding: const EdgeInsets.all(2.0),
|
||||
labelPadding: const EdgeInsets.only(top: 8.0, bottom: 8.0),
|
||||
shape: const BeveledRectangleBorder(),
|
||||
side: const BorderSide(color: Colors.white),
|
||||
elevation: 5.0,
|
||||
pressElevation: 10.0,
|
||||
shadowColor: Colors.white,
|
||||
|
@ -264,7 +271,8 @@ void main() {
|
|||
expect(lerp.selectedShadowColor, equals(middleGrey));
|
||||
expect(lerp.labelPadding, equals(const EdgeInsets.all(4.0)));
|
||||
expect(lerp.padding, equals(const EdgeInsets.all(3.0)));
|
||||
expect(lerp.shape, isA<StadiumBorder>());
|
||||
expect(lerp.side!.color, equals(middleGrey));
|
||||
expect(lerp.shape, isA<BeveledRectangleBorder>());
|
||||
expect(lerp.labelStyle.color, equals(middleGrey.withAlpha(0xde)));
|
||||
expect(lerp.secondaryLabelStyle.color, equals(middleGrey.withAlpha(0xde)));
|
||||
expect(lerp.brightness, equals(Brightness.light));
|
||||
|
@ -284,7 +292,8 @@ void main() {
|
|||
expect(lerpANull25.selectedShadowColor, equals(Colors.white.withAlpha(0x40)));
|
||||
expect(lerpANull25.labelPadding, equals(const EdgeInsets.only(left: 0.0, top: 2.0, right: 0.0, bottom: 2.0)));
|
||||
expect(lerpANull25.padding, equals(const EdgeInsets.all(0.5)));
|
||||
expect(lerpANull25.shape, isA<StadiumBorder>());
|
||||
expect(lerpANull25.side!.color, equals(Colors.white.withAlpha(0x3f)));
|
||||
expect(lerpANull25.shape, isA<BeveledRectangleBorder>());
|
||||
expect(lerpANull25.labelStyle.color, equals(Colors.black.withAlpha(0x38)));
|
||||
expect(lerpANull25.secondaryLabelStyle.color, equals(Colors.white.withAlpha(0x38)));
|
||||
expect(lerpANull25.brightness, equals(Brightness.light));
|
||||
|
@ -302,7 +311,8 @@ void main() {
|
|||
expect(lerpANull75.selectedShadowColor, equals(Colors.white.withAlpha(0xbf)));
|
||||
expect(lerpANull75.labelPadding, equals(const EdgeInsets.only(left: 0.0, top: 6.0, right: 0.0, bottom: 6.0)));
|
||||
expect(lerpANull75.padding, equals(const EdgeInsets.all(1.5)));
|
||||
expect(lerpANull75.shape, isA<StadiumBorder>());
|
||||
expect(lerpANull75.side!.color, equals(Colors.white.withAlpha(0xbf)));
|
||||
expect(lerpANull75.shape, isA<BeveledRectangleBorder>());
|
||||
expect(lerpANull75.labelStyle.color, equals(Colors.black.withAlpha(0xa7)));
|
||||
expect(lerpANull75.secondaryLabelStyle.color, equals(Colors.white.withAlpha(0xa7)));
|
||||
expect(lerpANull75.brightness, equals(Brightness.light));
|
||||
|
@ -320,6 +330,7 @@ void main() {
|
|||
expect(lerpBNull25.selectedShadowColor, equals(Colors.black.withAlpha(0xbf)));
|
||||
expect(lerpBNull25.labelPadding, equals(const EdgeInsets.only(left: 6.0, top: 0.0, right: 6.0, bottom: 0.0)));
|
||||
expect(lerpBNull25.padding, equals(const EdgeInsets.all(3.0)));
|
||||
expect(lerpBNull25.side!.color, equals(Colors.black.withAlpha(0x3f)));
|
||||
expect(lerpBNull25.shape, isA<StadiumBorder>());
|
||||
expect(lerpBNull25.labelStyle.color, equals(Colors.white.withAlpha(0xa7)));
|
||||
expect(lerpBNull25.secondaryLabelStyle.color, equals(Colors.black.withAlpha(0xa7)));
|
||||
|
@ -338,6 +349,7 @@ void main() {
|
|||
expect(lerpBNull75.selectedShadowColor, equals(Colors.black.withAlpha(0x40)));
|
||||
expect(lerpBNull75.labelPadding, equals(const EdgeInsets.only(left: 2.0, top: 0.0, right: 2.0, bottom: 0.0)));
|
||||
expect(lerpBNull75.padding, equals(const EdgeInsets.all(1.0)));
|
||||
expect(lerpBNull75.side!.color, equals(Colors.black.withAlpha(0xbf)));
|
||||
expect(lerpBNull75.shape, isA<StadiumBorder>());
|
||||
expect(lerpBNull75.labelStyle.color, equals(Colors.white.withAlpha(0x38)));
|
||||
expect(lerpBNull75.secondaryLabelStyle.color, equals(Colors.black.withAlpha(0x38)));
|
||||
|
@ -440,4 +452,95 @@ void main() {
|
|||
// Teardown.
|
||||
await gesture.removePointer();
|
||||
});
|
||||
|
||||
testWidgets('Chip uses stateful border side from chip theme', (WidgetTester tester) async {
|
||||
const Color selectedColor = Color(0x00000001);
|
||||
const Color defaultColor = Color(0x00000002);
|
||||
|
||||
BorderSide getBorderSide(Set<MaterialState> states) {
|
||||
Color color = defaultColor;
|
||||
|
||||
if (states.contains(MaterialState.selected))
|
||||
color = selectedColor;
|
||||
|
||||
return BorderSide(color: color, width: 1);
|
||||
}
|
||||
|
||||
Widget chipWidget({ bool selected = false }) {
|
||||
return MaterialApp(
|
||||
theme: ThemeData(
|
||||
chipTheme: ThemeData.light().chipTheme.copyWith(
|
||||
side: _MaterialStateBorderSide(getBorderSide),
|
||||
),
|
||||
),
|
||||
home: Scaffold(
|
||||
body: ChoiceChip(
|
||||
label: const Text('Chip'),
|
||||
selected: selected,
|
||||
onSelected: (_) {},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Default.
|
||||
await tester.pumpWidget(chipWidget());
|
||||
expect(find.byType(RawChip), paints..rrect(color: defaultColor));
|
||||
|
||||
// Selected.
|
||||
await tester.pumpWidget(chipWidget(selected: true));
|
||||
expect(find.byType(RawChip), paints..rrect(color: selectedColor));
|
||||
});
|
||||
|
||||
testWidgets('Chip uses stateful shape from chip theme', (WidgetTester tester) async {
|
||||
OutlinedBorder? getShape(Set<MaterialState> states) {
|
||||
if (states.contains(MaterialState.selected))
|
||||
return const RoundedRectangleBorder();
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
Widget chipWidget({ bool selected = false }) {
|
||||
return MaterialApp(
|
||||
theme: ThemeData(
|
||||
chipTheme: ThemeData.light().chipTheme.copyWith(
|
||||
shape: _MaterialStateOutlinedBorder(getShape),
|
||||
),
|
||||
),
|
||||
home: Scaffold(
|
||||
body: ChoiceChip(
|
||||
label: const Text('Chip'),
|
||||
selected: selected,
|
||||
onSelected: (_) {},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Default.
|
||||
await tester.pumpWidget(chipWidget());
|
||||
expect(getMaterial(tester).shape, isA<StadiumBorder>());
|
||||
|
||||
// Selected.
|
||||
await tester.pumpWidget(chipWidget(selected: true));
|
||||
expect(getMaterial(tester).shape, isA<RoundedRectangleBorder>());
|
||||
});
|
||||
}
|
||||
|
||||
class _MaterialStateOutlinedBorder extends StadiumBorder implements MaterialStateOutlinedBorder {
|
||||
const _MaterialStateOutlinedBorder(this.resolver);
|
||||
|
||||
final MaterialPropertyResolver<OutlinedBorder?> resolver;
|
||||
|
||||
@override
|
||||
OutlinedBorder? resolve(Set<MaterialState> states) => resolver(states);
|
||||
}
|
||||
|
||||
class _MaterialStateBorderSide extends MaterialStateBorderSide {
|
||||
const _MaterialStateBorderSide(this.resolver);
|
||||
|
||||
final MaterialPropertyResolver<BorderSide?> resolver;
|
||||
|
||||
@override
|
||||
BorderSide? resolve(Set<MaterialState> states) => resolver(states);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue