mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
Make CupertinoRadio
's mouseCursor
a WidgetStateProperty
(#151910)
https://github.com/flutter/flutter/pull/149681 introduced `mouseCursor `to `CupertinoRadio` as a `MouseCursor` instead of a `WidgetStateProperty` to match Material Radio's `mouseCursor` property for `.adaptive`. This PR changes `mouseCursor` to be of type `WidgetStateProperty<MouseCursor>` as per review comments in https://github.com/flutter/flutter/pull/151788#discussion_r1680538286. PR bringing `mouseCursor` into `CupertinoRadio`: https://github.com/flutter/flutter/pull/149681. Part of https://github.com/flutter/flutter/issues/58192
This commit is contained in:
parent
14f9b568fc
commit
5ef969a24f
@ -132,24 +132,20 @@ class CupertinoRadio<T> extends StatefulWidget {
|
|||||||
/// The cursor for a mouse pointer when it enters or is hovering over the
|
/// The cursor for a mouse pointer when it enters or is hovering over the
|
||||||
/// widget.
|
/// widget.
|
||||||
///
|
///
|
||||||
/// If [mouseCursor] is a [WidgetStateMouseCursor],
|
/// Resolves in the following states:
|
||||||
/// [WidgetStateMouseCursor.resolve] is used for the following [WidgetState]s:
|
|
||||||
///
|
///
|
||||||
/// * [WidgetState.selected].
|
/// * [WidgetState.selected].
|
||||||
/// * [WidgetState.hovered].
|
|
||||||
/// * [WidgetState.focused].
|
/// * [WidgetState.focused].
|
||||||
/// * [WidgetState.disabled].
|
/// * [WidgetState.disabled].
|
||||||
///
|
///
|
||||||
/// If null, then [SystemMouseCursors.basic] is used when this radio button is disabled.
|
/// Defaults to [defaultMouseCursor].
|
||||||
/// When this radio button is enabled, [SystemMouseCursors.click] is used on Web, and
|
|
||||||
/// [SystemMouseCursors.basic] is used on other platforms.
|
|
||||||
///
|
///
|
||||||
/// See also:
|
/// See also:
|
||||||
///
|
///
|
||||||
/// * [WidgetStateMouseCursor], a [MouseCursor] that implements
|
/// * [WidgetStateMouseCursor], a [MouseCursor] that implements
|
||||||
/// `WidgetStateProperty` which is used in APIs that need to accept
|
/// `WidgetStateProperty` which is used in APIs that need to accept
|
||||||
/// either a [MouseCursor] or a [WidgetStateProperty<MouseCursor>].
|
/// either a [MouseCursor] or a [WidgetStateProperty].
|
||||||
final MouseCursor? mouseCursor;
|
final WidgetStateProperty<MouseCursor>? mouseCursor;
|
||||||
|
|
||||||
/// Set to true if this radio button is allowed to be returned to an
|
/// Set to true if this radio button is allowed to be returned to an
|
||||||
/// indeterminate state by selecting it again when selected.
|
/// indeterminate state by selecting it again when selected.
|
||||||
@ -210,6 +206,18 @@ class CupertinoRadio<T> extends StatefulWidget {
|
|||||||
|
|
||||||
bool get _selected => value == groupValue;
|
bool get _selected => value == groupValue;
|
||||||
|
|
||||||
|
/// The default [mouseCursor] of a [CupertinoRadio].
|
||||||
|
///
|
||||||
|
/// If [onChanged] is null, indicating the radio button is disabled,
|
||||||
|
/// [SystemMouseCursors.basic] is used. Otherwise, [SystemMouseCursors.click]
|
||||||
|
/// is used on Web, and [SystemMouseCursors.basic] is used on other platforms.
|
||||||
|
static WidgetStateProperty<MouseCursor> defaultMouseCursor(Function? onChanged) {
|
||||||
|
final MouseCursor mouseCursor = (onChanged != null && kIsWeb)
|
||||||
|
? SystemMouseCursors.click
|
||||||
|
: SystemMouseCursors.basic;
|
||||||
|
return WidgetStateProperty.all<MouseCursor>(mouseCursor);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<CupertinoRadio<T>> createState() => _CupertinoRadioState<T>();
|
State<CupertinoRadio<T>> createState() => _CupertinoRadioState<T>();
|
||||||
}
|
}
|
||||||
@ -269,15 +277,6 @@ class _CupertinoRadioState<T> extends State<CupertinoRadio<T>> with TickerProvid
|
|||||||
|
|
||||||
final Color effectiveFillColor = widget.fillColor ?? CupertinoColors.white;
|
final Color effectiveFillColor = widget.fillColor ?? CupertinoColors.white;
|
||||||
|
|
||||||
final WidgetStateProperty<MouseCursor> effectiveMouseCursor =
|
|
||||||
WidgetStateProperty.resolveWith<MouseCursor>((Set<WidgetState> states) {
|
|
||||||
return WidgetStateProperty.resolveAs<MouseCursor?>(widget.mouseCursor, states)
|
|
||||||
?? (states.contains(WidgetState.disabled)
|
|
||||||
? SystemMouseCursors.basic
|
|
||||||
: kIsWeb ? SystemMouseCursors.click : SystemMouseCursors.basic
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
final bool? accessibilitySelected;
|
final bool? accessibilitySelected;
|
||||||
// Apple devices also use `selected` to annotate radio button's semantics
|
// Apple devices also use `selected` to annotate radio button's semantics
|
||||||
// state.
|
// state.
|
||||||
@ -297,7 +296,7 @@ class _CupertinoRadioState<T> extends State<CupertinoRadio<T>> with TickerProvid
|
|||||||
checked: widget._selected,
|
checked: widget._selected,
|
||||||
selected: accessibilitySelected,
|
selected: accessibilitySelected,
|
||||||
child: buildToggleable(
|
child: buildToggleable(
|
||||||
mouseCursor: effectiveMouseCursor,
|
mouseCursor: widget.mouseCursor ?? CupertinoRadio.defaultMouseCursor(widget.onChanged),
|
||||||
focusNode: widget.focusNode,
|
focusNode: widget.focusNode,
|
||||||
autofocus: widget.autofocus,
|
autofocus: widget.autofocus,
|
||||||
onFocusChange: onFocusChange,
|
onFocusChange: onFocusChange,
|
||||||
|
@ -447,7 +447,11 @@ class _RadioState<T> extends State<Radio<T>> with TickerProviderStateMixin, Togg
|
|||||||
value: widget.value,
|
value: widget.value,
|
||||||
groupValue: widget.groupValue,
|
groupValue: widget.groupValue,
|
||||||
onChanged: widget.onChanged,
|
onChanged: widget.onChanged,
|
||||||
mouseCursor: widget.mouseCursor,
|
mouseCursor: widget.mouseCursor == null
|
||||||
|
? CupertinoRadio.defaultMouseCursor(widget.onChanged)
|
||||||
|
: WidgetStateProperty.resolveWith((Set<MaterialState> states) {
|
||||||
|
return WidgetStateProperty.resolveAs<MouseCursor>(widget.mouseCursor!, states);
|
||||||
|
}),
|
||||||
toggleable: widget.toggleable,
|
toggleable: widget.toggleable,
|
||||||
activeColor: widget.activeColor,
|
activeColor: widget.activeColor,
|
||||||
focusColor: widget.focusColor,
|
focusColor: widget.focusColor,
|
||||||
|
@ -441,7 +441,7 @@ void main() {
|
|||||||
value: 1,
|
value: 1,
|
||||||
groupValue: 1,
|
groupValue: 1,
|
||||||
onChanged: (int? i) { },
|
onChanged: (int? i) { },
|
||||||
mouseCursor: SystemMouseCursors.forbidden,
|
mouseCursor: WidgetStateProperty.all(SystemMouseCursors.forbidden),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
@ -463,13 +463,25 @@ void main() {
|
|||||||
final FocusNode focusNode = FocusNode(debugLabel: 'Radio');
|
final FocusNode focusNode = FocusNode(debugLabel: 'Radio');
|
||||||
tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
|
tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
|
||||||
|
|
||||||
|
MouseCursor getMouseCursor(Set<WidgetState> states) {
|
||||||
|
if (states.contains(WidgetState.disabled)) {
|
||||||
|
return SystemMouseCursors.forbidden;
|
||||||
|
}
|
||||||
|
if (states.contains(WidgetState.focused)) {
|
||||||
|
return SystemMouseCursors.basic;
|
||||||
|
}
|
||||||
|
return SystemMouseCursors.click;
|
||||||
|
}
|
||||||
|
|
||||||
|
final WidgetStateProperty<MouseCursor> mouseCursor = WidgetStateProperty.resolveWith(getMouseCursor);
|
||||||
|
|
||||||
await tester.pumpWidget(CupertinoApp(
|
await tester.pumpWidget(CupertinoApp(
|
||||||
home: Center(
|
home: Center(
|
||||||
child: CupertinoRadio<int>(
|
child: CupertinoRadio<int>(
|
||||||
value: 1,
|
value: 1,
|
||||||
groupValue: 1,
|
groupValue: 1,
|
||||||
onChanged: (int? i) { },
|
onChanged: (int? i) { },
|
||||||
mouseCursor: const RadioMouseCursor(),
|
mouseCursor: mouseCursor,
|
||||||
focusNode: focusNode
|
focusNode: focusNode
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -498,13 +510,13 @@ void main() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Test disabled case.
|
// Test disabled case.
|
||||||
await tester.pumpWidget(const CupertinoApp(
|
await tester.pumpWidget(CupertinoApp(
|
||||||
home: Center(
|
home: Center(
|
||||||
child: CupertinoRadio<int>(
|
child: CupertinoRadio<int>(
|
||||||
value: 1,
|
value: 1,
|
||||||
groupValue: 1,
|
groupValue: 1,
|
||||||
onChanged: null,
|
onChanged: null,
|
||||||
mouseCursor: RadioMouseCursor(),
|
mouseCursor: mouseCursor,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
@ -541,21 +553,3 @@ void main() {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
class RadioMouseCursor extends WidgetStateMouseCursor {
|
|
||||||
const RadioMouseCursor();
|
|
||||||
|
|
||||||
@override
|
|
||||||
MouseCursor resolve(Set<WidgetState> states) {
|
|
||||||
if (states.contains(WidgetState.disabled)) {
|
|
||||||
return SystemMouseCursors.forbidden;
|
|
||||||
}
|
|
||||||
if (states.contains(WidgetState.focused)){
|
|
||||||
return SystemMouseCursors.basic;
|
|
||||||
}
|
|
||||||
return SystemMouseCursors.click;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get debugDescription => 'RadioMouseCursor()';
|
|
||||||
}
|
|
||||||
|
@ -1859,6 +1859,46 @@ void main() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('Radio.adaptive respects Radio.mouseCursor', (WidgetTester tester) async {
|
||||||
|
Widget buildApp({required TargetPlatform platform, MouseCursor? mouseCursor}) {
|
||||||
|
return MaterialApp(
|
||||||
|
theme: ThemeData(platform: platform),
|
||||||
|
home: Material(
|
||||||
|
child: Radio<int>.adaptive(
|
||||||
|
value: 1,
|
||||||
|
groupValue: 1,
|
||||||
|
onChanged: (int? i) {},
|
||||||
|
mouseCursor: mouseCursor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (final TargetPlatform platform in <TargetPlatform>[ TargetPlatform.iOS, TargetPlatform.macOS ]) {
|
||||||
|
await tester.pumpWidget(buildApp(platform: platform));
|
||||||
|
final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse, pointer: 1);
|
||||||
|
|
||||||
|
// Test default mouse cursor.
|
||||||
|
await gesture.addPointer(location: tester.getCenter(find.byType(CupertinoRadio<int>)));
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.moveTo(tester.getCenter(find.byType(CupertinoRadio<int>)));
|
||||||
|
expect(
|
||||||
|
RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1),
|
||||||
|
kIsWeb ? SystemMouseCursors.click : SystemMouseCursors.basic,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Test mouse cursor can be configured.
|
||||||
|
await tester.pumpWidget(buildApp(platform: platform, mouseCursor: SystemMouseCursors.forbidden));
|
||||||
|
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.forbidden);
|
||||||
|
|
||||||
|
// Test Radio.adaptive can resolve a WidgetStateMouseCursor.
|
||||||
|
await tester.pumpWidget(buildApp(platform: platform, mouseCursor: const _SelectedGrabMouseCursor()));
|
||||||
|
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.grab);
|
||||||
|
|
||||||
|
await gesture.removePointer();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
testWidgets('Material2 - Radio default overlayColor and fillColor resolves pressed state', (WidgetTester tester) async {
|
testWidgets('Material2 - Radio default overlayColor and fillColor resolves pressed state', (WidgetTester tester) async {
|
||||||
final FocusNode focusNode = FocusNode(debugLabel: 'Radio');
|
final FocusNode focusNode = FocusNode(debugLabel: 'Radio');
|
||||||
tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
|
tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
|
||||||
@ -1993,3 +2033,18 @@ void main() {
|
|||||||
focusNode.dispose();
|
focusNode.dispose();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class _SelectedGrabMouseCursor extends WidgetStateMouseCursor {
|
||||||
|
const _SelectedGrabMouseCursor();
|
||||||
|
|
||||||
|
@override
|
||||||
|
MouseCursor resolve(Set<WidgetState> states) {
|
||||||
|
if (states.contains(WidgetState.selected)) {
|
||||||
|
return SystemMouseCursors.grab;
|
||||||
|
}
|
||||||
|
return SystemMouseCursors.basic;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get debugDescription => '_SelectedGrabMouseCursor()';
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user