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
|
||||
/// widget.
|
||||
///
|
||||
/// If [mouseCursor] is a [WidgetStateMouseCursor],
|
||||
/// [WidgetStateMouseCursor.resolve] is used for the following [WidgetState]s:
|
||||
/// Resolves in the following states:
|
||||
///
|
||||
/// * [WidgetState.selected].
|
||||
/// * [WidgetState.hovered].
|
||||
/// * [WidgetState.focused].
|
||||
/// * [WidgetState.disabled].
|
||||
///
|
||||
/// If null, then [SystemMouseCursors.basic] is used when this radio button is disabled.
|
||||
/// When this radio button is enabled, [SystemMouseCursors.click] is used on Web, and
|
||||
/// [SystemMouseCursors.basic] is used on other platforms.
|
||||
/// Defaults to [defaultMouseCursor].
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [WidgetStateMouseCursor], a [MouseCursor] that implements
|
||||
/// `WidgetStateProperty` which is used in APIs that need to accept
|
||||
/// either a [MouseCursor] or a [WidgetStateProperty<MouseCursor>].
|
||||
final MouseCursor? mouseCursor;
|
||||
/// either a [MouseCursor] or a [WidgetStateProperty].
|
||||
final WidgetStateProperty<MouseCursor>? mouseCursor;
|
||||
|
||||
/// Set to true if this radio button is allowed to be returned to an
|
||||
/// indeterminate state by selecting it again when selected.
|
||||
@ -210,6 +206,18 @@ class CupertinoRadio<T> extends StatefulWidget {
|
||||
|
||||
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
|
||||
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 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;
|
||||
// Apple devices also use `selected` to annotate radio button's semantics
|
||||
// state.
|
||||
@ -297,7 +296,7 @@ class _CupertinoRadioState<T> extends State<CupertinoRadio<T>> with TickerProvid
|
||||
checked: widget._selected,
|
||||
selected: accessibilitySelected,
|
||||
child: buildToggleable(
|
||||
mouseCursor: effectiveMouseCursor,
|
||||
mouseCursor: widget.mouseCursor ?? CupertinoRadio.defaultMouseCursor(widget.onChanged),
|
||||
focusNode: widget.focusNode,
|
||||
autofocus: widget.autofocus,
|
||||
onFocusChange: onFocusChange,
|
||||
|
@ -447,7 +447,11 @@ class _RadioState<T> extends State<Radio<T>> with TickerProviderStateMixin, Togg
|
||||
value: widget.value,
|
||||
groupValue: widget.groupValue,
|
||||
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,
|
||||
activeColor: widget.activeColor,
|
||||
focusColor: widget.focusColor,
|
||||
|
@ -441,7 +441,7 @@ void main() {
|
||||
value: 1,
|
||||
groupValue: 1,
|
||||
onChanged: (int? i) { },
|
||||
mouseCursor: SystemMouseCursors.forbidden,
|
||||
mouseCursor: WidgetStateProperty.all(SystemMouseCursors.forbidden),
|
||||
),
|
||||
),
|
||||
));
|
||||
@ -463,13 +463,25 @@ void main() {
|
||||
final FocusNode focusNode = FocusNode(debugLabel: 'Radio');
|
||||
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(
|
||||
home: Center(
|
||||
child: CupertinoRadio<int>(
|
||||
value: 1,
|
||||
groupValue: 1,
|
||||
onChanged: (int? i) { },
|
||||
mouseCursor: const RadioMouseCursor(),
|
||||
mouseCursor: mouseCursor,
|
||||
focusNode: focusNode
|
||||
),
|
||||
),
|
||||
@ -498,13 +510,13 @@ void main() {
|
||||
);
|
||||
|
||||
// Test disabled case.
|
||||
await tester.pumpWidget(const CupertinoApp(
|
||||
await tester.pumpWidget(CupertinoApp(
|
||||
home: Center(
|
||||
child: CupertinoRadio<int>(
|
||||
value: 1,
|
||||
groupValue: 1,
|
||||
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 {
|
||||
final FocusNode focusNode = FocusNode(debugLabel: 'Radio');
|
||||
tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
|
||||
@ -1993,3 +2033,18 @@ void main() {
|
||||
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