Skip to content

Commit fbb3036

Browse files
authored
FloatingActionButton: add themeable mouse cursor (#103473)
1 parent 2756f86 commit fbb3036

File tree

3 files changed

+67
-3
lines changed

3 files changed

+67
-3
lines changed

packages/flutter/lib/src/material/floating_action_button.dart

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import 'package:flutter/widgets.dart';
1111
import 'button.dart';
1212
import 'color_scheme.dart';
1313
import 'floating_action_button_theme.dart';
14+
import 'material_state.dart';
1415
import 'scaffold.dart';
1516
import 'text_theme.dart';
1617
import 'theme.dart';
@@ -603,7 +604,7 @@ class FloatingActionButton extends StatelessWidget {
603604

604605
Widget result = RawMaterialButton(
605606
onPressed: onPressed,
606-
mouseCursor: mouseCursor,
607+
mouseCursor: _EffectiveMouseCursor(mouseCursor, floatingActionButtonTheme.mouseCursor),
607608
elevation: elevation,
608609
focusElevation: focusElevation,
609610
hoverElevation: hoverElevation,
@@ -664,6 +665,26 @@ class FloatingActionButton extends StatelessWidget {
664665
}
665666
}
666667

668+
// This MaterialStateProperty is passed along to RawMaterialButton which
669+
// resolves the property against MaterialState.pressed, MaterialState.hovered,
670+
// MaterialState.focused, MaterialState.disabled.
671+
class _EffectiveMouseCursor extends MaterialStateMouseCursor {
672+
const _EffectiveMouseCursor(this.widgetCursor, this.themeCursor);
673+
674+
final MouseCursor? widgetCursor;
675+
final MaterialStateProperty<MouseCursor?>? themeCursor;
676+
677+
@override
678+
MouseCursor resolve(Set<MaterialState> states) {
679+
return MaterialStateProperty.resolveAs<MouseCursor?>(widgetCursor, states)
680+
?? themeCursor?.resolve(states)
681+
?? MaterialStateMouseCursor.clickable.resolve(states);
682+
}
683+
684+
@override
685+
String get debugDescription => 'MaterialStateMouseCursor(FloatActionButton)';
686+
}
687+
667688
// This widget's size matches its child's size unless its constraints
668689
// force it to be larger or smaller. The child is centered.
669690
//

packages/flutter/lib/src/material/floating_action_button_theme.dart

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import 'dart:ui' show lerpDouble;
77
import 'package:flutter/foundation.dart';
88
import 'package:flutter/rendering.dart';
99

10+
import 'material_state.dart';
11+
1012
/// Defines default property values for descendant [FloatingActionButton]
1113
/// widgets.
1214
///
@@ -51,6 +53,7 @@ class FloatingActionButtonThemeData with Diagnosticable {
5153
this.extendedIconLabelSpacing,
5254
this.extendedPadding,
5355
this.extendedTextStyle,
56+
this.mouseCursor,
5457
});
5558

5659
/// Color to be used for the unselected, enabled [FloatingActionButton]'s
@@ -129,6 +132,11 @@ class FloatingActionButtonThemeData with Diagnosticable {
129132
/// The text style for an extended [FloatingActionButton]'s label.
130133
final TextStyle? extendedTextStyle;
131134

135+
/// {@macro flutter.material.RawMaterialButton.mouseCursor}
136+
///
137+
/// If specified, overrides the default value of [FloatingActionButton.mouseCursor].
138+
final MaterialStateProperty<MouseCursor?>? mouseCursor;
139+
132140
/// Creates a copy of this object with the given fields replaced with the
133141
/// new values.
134142
FloatingActionButtonThemeData copyWith({
@@ -152,6 +160,7 @@ class FloatingActionButtonThemeData with Diagnosticable {
152160
double? extendedIconLabelSpacing,
153161
EdgeInsetsGeometry? extendedPadding,
154162
TextStyle? extendedTextStyle,
163+
MaterialStateProperty<MouseCursor?>? mouseCursor,
155164
}) {
156165
return FloatingActionButtonThemeData(
157166
foregroundColor: foregroundColor ?? this.foregroundColor,
@@ -174,6 +183,7 @@ class FloatingActionButtonThemeData with Diagnosticable {
174183
extendedIconLabelSpacing: extendedIconLabelSpacing ?? this.extendedIconLabelSpacing,
175184
extendedPadding: extendedPadding ?? this.extendedPadding,
176185
extendedTextStyle: extendedTextStyle ?? this.extendedTextStyle,
186+
mouseCursor: mouseCursor ?? this.mouseCursor,
177187
);
178188
}
179189

@@ -208,6 +218,7 @@ class FloatingActionButtonThemeData with Diagnosticable {
208218
extendedIconLabelSpacing: lerpDouble(a?.extendedIconLabelSpacing, b?.extendedIconLabelSpacing, t),
209219
extendedPadding: EdgeInsetsGeometry.lerp(a?.extendedPadding, b?.extendedPadding, t),
210220
extendedTextStyle: TextStyle.lerp(a?.extendedTextStyle, b?.extendedTextStyle, t),
221+
mouseCursor: t < 0.5 ? a?.mouseCursor : b?.mouseCursor,
211222
);
212223
}
213224

@@ -232,7 +243,10 @@ class FloatingActionButtonThemeData with Diagnosticable {
232243
extendedSizeConstraints,
233244
extendedIconLabelSpacing,
234245
extendedPadding,
235-
extendedTextStyle,
246+
Object.hash(
247+
extendedTextStyle,
248+
mouseCursor,
249+
),
236250
);
237251

238252
@override
@@ -263,7 +277,8 @@ class FloatingActionButtonThemeData with Diagnosticable {
263277
&& other.extendedSizeConstraints == extendedSizeConstraints
264278
&& other.extendedIconLabelSpacing == extendedIconLabelSpacing
265279
&& other.extendedPadding == extendedPadding
266-
&& other.extendedTextStyle == extendedTextStyle;
280+
&& other.extendedTextStyle == extendedTextStyle
281+
&& other.mouseCursor == mouseCursor;
267282
}
268283

269284
@override
@@ -290,5 +305,6 @@ class FloatingActionButtonThemeData with Diagnosticable {
290305
properties.add(DoubleProperty('extendedIconLabelSpacing', extendedIconLabelSpacing, defaultValue: null));
291306
properties.add(DiagnosticsProperty<EdgeInsetsGeometry>('extendedPadding', extendedPadding, defaultValue: null));
292307
properties.add(DiagnosticsProperty<TextStyle>('extendedTextStyle', extendedTextStyle, defaultValue: null));
308+
properties.add(DiagnosticsProperty<MaterialStateProperty<MouseCursor?>>('mouseCursor', mouseCursor, defaultValue: null));
293309
}
294310
}

packages/flutter/test/material/floating_action_button_theme_test.dart

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5+
import 'package:flutter/gestures.dart';
56
import 'package:flutter/material.dart';
67
import 'package:flutter/rendering.dart';
78
import 'package:flutter_test/flutter_test.dart';
@@ -287,6 +288,7 @@ void main() {
287288
extendedIconLabelSpacing: 12,
288289
extendedPadding: EdgeInsetsDirectional.only(start: 7.0, end: 8.0),
289290
extendedTextStyle: TextStyle(letterSpacing: 2.0),
291+
mouseCursor: MaterialStateMouseCursor.clickable,
290292
).debugFillProperties(builder);
291293

292294
final List<String> description = builder.properties
@@ -315,8 +317,33 @@ void main() {
315317
'extendedIconLabelSpacing: 12.0',
316318
'extendedPadding: EdgeInsetsDirectional(7.0, 0.0, 8.0, 0.0)',
317319
'extendedTextStyle: TextStyle(inherit: true, letterSpacing: 2.0)',
320+
'mouseCursor: MaterialStateMouseCursor(clickable)',
318321
]);
319322
});
323+
324+
testWidgets('FloatingActionButton.mouseCursor uses FloatingActionButtonThemeData.mouseCursor when specified.', (WidgetTester tester) async {
325+
await tester.pumpWidget(MaterialApp(
326+
theme: ThemeData().copyWith(
327+
floatingActionButtonTheme: FloatingActionButtonThemeData(
328+
mouseCursor: MaterialStateProperty.all(SystemMouseCursors.text),
329+
),
330+
),
331+
home: Scaffold(
332+
floatingActionButton: FloatingActionButton(
333+
onPressed: () { },
334+
child: const Icon(Icons.add),
335+
),
336+
),
337+
));
338+
339+
await tester.pumpAndSettle();
340+
final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse);
341+
await gesture.addPointer();
342+
addTearDown(gesture.removePointer);
343+
await gesture.moveTo(tester.getCenter(find.byType(FloatingActionButton)));
344+
await tester.pumpAndSettle();
345+
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.text);
346+
});
320347
}
321348

322349
RawMaterialButton _getRawMaterialButton(WidgetTester tester) {

0 commit comments

Comments
 (0)