Feat: Add fillColor property for cupertinoCheckbox (#151761)
Feat: Add `fillColor` property for `CupertinoCheckbox` Required for #151252
This commit is contained in:
parent
93b55edff1
commit
a9b2d8d6d4
@ -104,6 +104,7 @@ class CupertinoCheckbox extends StatefulWidget {
|
||||
required this.onChanged,
|
||||
this.activeColor,
|
||||
this.inactiveColor,
|
||||
this.fillColor,
|
||||
this.checkColor,
|
||||
this.focusColor,
|
||||
this.focusNode,
|
||||
@ -152,11 +153,51 @@ class CupertinoCheckbox extends StatefulWidget {
|
||||
|
||||
/// The color to use when this checkbox is checked.
|
||||
///
|
||||
/// If [fillColor] returns a non-null color in the [WidgetState.selected]
|
||||
/// state, [fillColor] will be used instead of [activeColor].
|
||||
///
|
||||
/// Defaults to [CupertinoColors.activeBlue].
|
||||
final Color? activeColor;
|
||||
|
||||
/// {@template flutter.cupertino.CupertinoCheckbox.fillColor}
|
||||
/// The color used to fill this checkbox.
|
||||
///
|
||||
/// Resolves in the following states:
|
||||
/// * [WidgetState.selected].
|
||||
/// * [WidgetState.hovered].
|
||||
/// * [WidgetState.focused].
|
||||
/// * [WidgetState.disabled].
|
||||
///
|
||||
/// {@tool snippet}
|
||||
/// This example resolves the [fillColor] based on the current [WidgetState]
|
||||
/// of the [CupertinoCheckbox], providing a different [Color] when it is
|
||||
/// [WidgetState.disabled].
|
||||
///
|
||||
/// ```dart
|
||||
/// CupertinoCheckbox(
|
||||
/// value: true,
|
||||
/// onChanged: (_){},
|
||||
/// fillColor: WidgetStateProperty.resolveWith<Color>((Set<WidgetState> states) {
|
||||
/// if (states.contains(WidgetState.disabled)) {
|
||||
/// return Colors.orange.withOpacity(.32);
|
||||
/// }
|
||||
/// return Colors.orange;
|
||||
/// })
|
||||
/// )
|
||||
/// ```
|
||||
/// {@end-tool}
|
||||
/// {@endtemplate}
|
||||
///
|
||||
/// If [fillColor] resolves to null for the requested state, then the fill color
|
||||
/// falls back to [activeColor] if the state includes [WidgetState.selected],
|
||||
/// or [inactiveColor] otherwise.
|
||||
final WidgetStateProperty<Color?>? fillColor;
|
||||
|
||||
/// The color used if the checkbox is inactive.
|
||||
///
|
||||
/// If [fillColor] returns a non-null color in the unselected
|
||||
/// state, [fillColor] will be used instead of [inactiveColor].
|
||||
///
|
||||
/// By default, [CupertinoColors.inactiveGray] is used.
|
||||
final Color? inactiveColor;
|
||||
|
||||
@ -318,6 +359,7 @@ class _CupertinoCheckboxState extends State<CupertinoCheckbox> with TickerProvid
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// Colors need to be resolved in selected and non selected states separately.
|
||||
// The `states` getter constructs a new set every time, making it safe to edit in place.
|
||||
final Set<WidgetState> activeStates = states..add(WidgetState.selected);
|
||||
final Set<WidgetState> inactiveStates = states..remove(WidgetState.selected);
|
||||
|
||||
@ -325,7 +367,11 @@ class _CupertinoCheckboxState extends State<CupertinoCheckbox> with TickerProvid
|
||||
// throughout the lifecycle of this build method.
|
||||
final Set<WidgetState> currentStates = states;
|
||||
|
||||
final Color effectiveActiveColor = _defaultFillColor.resolve(activeStates);
|
||||
final Color effectiveActiveColor = widget.fillColor?.resolve(activeStates)
|
||||
?? _defaultFillColor.resolve(activeStates);
|
||||
|
||||
final Color effectiveInactiveColor = widget.fillColor?.resolve(inactiveStates)
|
||||
?? _defaultFillColor.resolve(inactiveStates);
|
||||
|
||||
final BorderSide effectiveBorderSide = _resolveSide(widget.side, currentStates)
|
||||
?? _defaultSide.resolve(currentStates);
|
||||
@ -353,7 +399,7 @@ class _CupertinoCheckboxState extends State<CupertinoCheckbox> with TickerProvid
|
||||
..isFocused = currentStates.contains(WidgetState.focused)
|
||||
..isHovered = currentStates.contains(WidgetState.hovered)
|
||||
..activeColor = effectiveActiveColor
|
||||
..inactiveColor = _defaultFillColor.resolve(inactiveStates)
|
||||
..inactiveColor = effectiveInactiveColor
|
||||
..checkColor = _defaultCheckColor.resolve(currentStates)
|
||||
..value = value
|
||||
..previousValue = _previousValue
|
||||
|
@ -7,6 +7,7 @@
|
||||
// machines.
|
||||
@Tags(<String>['reduced-test-set'])
|
||||
library;
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
@ -575,6 +576,134 @@ void main() {
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Checkbox fill color resolves in enabled/disabled states', (WidgetTester tester) async {
|
||||
const Color activeEnabledFillColor = Color(0xFF000001);
|
||||
const Color activeDisabledFillColor = Color(0xFF000002);
|
||||
|
||||
Color getFillColor(Set<WidgetState> states) {
|
||||
if (states.contains(WidgetState.disabled)) {
|
||||
return activeDisabledFillColor;
|
||||
}
|
||||
return activeEnabledFillColor;
|
||||
}
|
||||
|
||||
final WidgetStateProperty<Color> fillColor = WidgetStateColor.resolveWith(getFillColor);
|
||||
|
||||
Widget buildApp({required bool enabled}) {
|
||||
return CupertinoApp(
|
||||
home: CupertinoCheckbox(
|
||||
value: true,
|
||||
fillColor: fillColor,
|
||||
onChanged: enabled ? (bool? value) { } : null,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
RenderBox getCheckboxRenderer() {
|
||||
return tester.renderObject<RenderBox>(find.byType(CupertinoCheckbox));
|
||||
}
|
||||
|
||||
await tester.pumpWidget(buildApp(enabled: true));
|
||||
await tester.pumpAndSettle();
|
||||
expect(getCheckboxRenderer(), paints..path(color: activeEnabledFillColor));
|
||||
|
||||
await tester.pumpWidget(buildApp(enabled: false));
|
||||
await tester.pumpAndSettle();
|
||||
expect(getCheckboxRenderer(), paints..path(color: activeDisabledFillColor));
|
||||
});
|
||||
|
||||
testWidgets('Checkbox fill color take precedence over active/inactive colors', (WidgetTester tester) async {
|
||||
const Color activeEnabledFillColor = Color(0xFF000001);
|
||||
const Color activeDisabledFillColor = Color(0xFF000002);
|
||||
const Color activeColor = Color(0xFF000003);
|
||||
const Color inactiveColor = Color(0xFF000004);
|
||||
|
||||
Color getFillColor(Set<WidgetState> states) {
|
||||
if (states.contains(WidgetState.disabled)) {
|
||||
return activeDisabledFillColor;
|
||||
}
|
||||
return activeEnabledFillColor;
|
||||
}
|
||||
|
||||
final WidgetStateProperty<Color> fillColor = WidgetStateColor.resolveWith(getFillColor);
|
||||
|
||||
Widget buildApp({required bool enabled}) {
|
||||
return CupertinoApp(
|
||||
home: CupertinoCheckbox(
|
||||
value: true,
|
||||
fillColor: fillColor,
|
||||
activeColor: activeColor,
|
||||
inactiveColor: inactiveColor,
|
||||
onChanged: enabled ? (bool? value) { } : null,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
RenderBox getCheckboxRenderer() {
|
||||
return tester.renderObject<RenderBox>(find.byType(CupertinoCheckbox));
|
||||
}
|
||||
|
||||
await tester.pumpWidget(buildApp(enabled: true));
|
||||
await tester.pumpAndSettle();
|
||||
expect(getCheckboxRenderer(), paints..path(color: activeEnabledFillColor));
|
||||
|
||||
await tester.pumpWidget(buildApp(enabled: false));
|
||||
await tester.pumpAndSettle();
|
||||
expect(getCheckboxRenderer(), paints..path(color: activeDisabledFillColor));
|
||||
});
|
||||
|
||||
testWidgets('Checkbox fill color resolves in hovered/focused states', (WidgetTester tester) async {
|
||||
final FocusNode focusNode = FocusNode(debugLabel: 'checkbox');
|
||||
addTearDown(focusNode.dispose);
|
||||
|
||||
tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
|
||||
const Color hoveredFillColor = Color(0xFF000001);
|
||||
const Color focusedFillColor = Color(0xFF000002);
|
||||
const Color transparentColor = Color(0x00000000);
|
||||
|
||||
Color getFillColor(Set<WidgetState> states) {
|
||||
if (states.contains(WidgetState.hovered)) {
|
||||
return hoveredFillColor;
|
||||
}
|
||||
if (states.contains(WidgetState.focused)) {
|
||||
return focusedFillColor;
|
||||
}
|
||||
return transparentColor;
|
||||
}
|
||||
|
||||
final WidgetStateProperty<Color> fillColor = WidgetStateColor.resolveWith(getFillColor);
|
||||
|
||||
Widget buildApp({required bool enabled}) {
|
||||
return CupertinoApp(
|
||||
home: CupertinoCheckbox(
|
||||
focusNode: focusNode,
|
||||
value: enabled,
|
||||
fillColor: fillColor,
|
||||
onChanged: enabled ? (bool? value) { } : null,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
RenderBox getCheckboxRenderer() {
|
||||
return tester.renderObject<RenderBox>(find.byType(CupertinoCheckbox));
|
||||
}
|
||||
|
||||
await tester.pumpWidget(buildApp(enabled: true));
|
||||
focusNode.requestFocus();
|
||||
await tester.pumpAndSettle();
|
||||
expect(focusNode.hasPrimaryFocus, isTrue);
|
||||
expect(getCheckboxRenderer(), paints..path(color: focusedFillColor));
|
||||
|
||||
// Start hovering.
|
||||
final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse);
|
||||
await gesture.addPointer();
|
||||
addTearDown(gesture.removePointer);
|
||||
await gesture.moveTo(tester.getCenter(find.byType(CupertinoCheckbox)));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(getCheckboxRenderer(), paints..path(color: hoveredFillColor));
|
||||
});
|
||||
|
||||
testWidgets('Checkbox configures focus color', (WidgetTester tester) async {
|
||||
const Color defaultCheckColor = Color(0xffffffff);
|
||||
const Color defaultActiveFillColor = Color(0xff007aff);
|
||||
|
Loading…
x
Reference in New Issue
Block a user