Skip to content

Commit 80d774d

Browse files
authored
Add DropdownMenu cursor behavior sample (#146133)
fixes [Add `DropdownMenu` cursor behavior sample to `DropdownMenu.enabled` & `DropdownMenu.requestFocusOnTap` docs](flutter/flutter#146131) ### Preview ![Screenshot 2024-04-02 at 17 12 43](https://github.com/flutter/flutter/assets/48603081/33865ca0-d48d-4651-9c83-9bdcd6369cb8)
1 parent e868e2b commit 80d774d

3 files changed

Lines changed: 226 additions & 0 deletions

File tree

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
// Copyright 2014 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'package:flutter/material.dart';
6+
7+
/// Flutter code sample for [DropdownMenu].
8+
9+
const List<String> list = <String>['One', 'Two', 'Three', 'Four'];
10+
11+
void main() => runApp(const DropdownMenuApp());
12+
13+
class DropdownMenuApp extends StatelessWidget {
14+
const DropdownMenuApp({super.key});
15+
16+
@override
17+
Widget build(BuildContext context) {
18+
return MaterialApp(
19+
home: Scaffold(
20+
appBar: AppBar(title: const Text('DropdownMenu Sample')),
21+
body: const Center(
22+
child: DropdownMenuExample(),
23+
),
24+
),
25+
);
26+
}
27+
}
28+
29+
class DropdownMenuExample extends StatefulWidget {
30+
const DropdownMenuExample({super.key});
31+
32+
@override
33+
State<DropdownMenuExample> createState() => _DropdownMenuExampleState();
34+
}
35+
36+
class _DropdownMenuExampleState extends State<DropdownMenuExample> {
37+
String dropdownValue = list.first;
38+
39+
@override
40+
Widget build(BuildContext context) {
41+
final ColorScheme colorScheme = Theme.of(context).colorScheme;
42+
43+
return ListView(
44+
children: <Widget>[
45+
ListTile(
46+
tileColor: colorScheme.primaryContainer,
47+
title: const Column(
48+
crossAxisAlignment: CrossAxisAlignment.start,
49+
children: <Widget>[
50+
Text('enabled: true'),
51+
Text('requestFocusOnTap: true'),
52+
],
53+
),
54+
subtitle: Column(
55+
children: <Widget>[
56+
DropdownMenu<String>(
57+
requestFocusOnTap: true,
58+
initialSelection: list.first,
59+
expandedInsets: EdgeInsets.zero,
60+
onSelected: (String? value) {
61+
setState(() {
62+
dropdownValue = value!;
63+
});
64+
},
65+
dropdownMenuEntries:
66+
list.map<DropdownMenuEntry<String>>((String value) {
67+
return DropdownMenuEntry<String>(value: value, label: value);
68+
}).toList(),
69+
),
70+
const Text('Text cursor is shown when hovering over the DropdownMenu.'),
71+
],
72+
),
73+
),
74+
const SizedBox(height: 20),
75+
ListTile(
76+
tileColor: colorScheme.primaryContainer,
77+
title: const Column(
78+
crossAxisAlignment: CrossAxisAlignment.start,
79+
children: <Widget>[
80+
Text('enabled: true'),
81+
Text('requestFocusOnTap: false'),
82+
],
83+
),
84+
subtitle: Column(
85+
children: <Widget>[
86+
DropdownMenu<String>(
87+
requestFocusOnTap: false,
88+
initialSelection: list.first,
89+
expandedInsets: EdgeInsets.zero,
90+
onSelected: (String? value) {
91+
setState(() {
92+
dropdownValue = value!;
93+
});
94+
},
95+
dropdownMenuEntries:
96+
list.map<DropdownMenuEntry<String>>((String value) {
97+
return DropdownMenuEntry<String>(value: value, label: value);
98+
}).toList(),
99+
),
100+
const Text('Clickable cursor is shown when hovering over the DropdownMenu.'),
101+
],
102+
),
103+
),
104+
const SizedBox(height: 20),
105+
ListTile(
106+
tileColor: colorScheme.onInverseSurface,
107+
title: const Column(
108+
crossAxisAlignment: CrossAxisAlignment.start,
109+
children: <Widget>[
110+
Text('enabled: false'),
111+
Text('requestFocusOnTap: true'),
112+
],
113+
),
114+
subtitle: Column(
115+
children: <Widget>[
116+
DropdownMenu<String>(
117+
enabled: false,
118+
requestFocusOnTap: true,
119+
initialSelection: list.first,
120+
expandedInsets: EdgeInsets.zero,
121+
onSelected: (String? value) {
122+
setState(() {
123+
dropdownValue = value!;
124+
});
125+
},
126+
dropdownMenuEntries:
127+
list.map<DropdownMenuEntry<String>>((String value) {
128+
return DropdownMenuEntry<String>(value: value, label: value);
129+
}).toList(),
130+
),
131+
const Text('Default cursor is shown when hovering over the DropdownMenu.'),
132+
],
133+
),
134+
),
135+
const SizedBox(height: 20),
136+
ListTile(
137+
tileColor: colorScheme.onInverseSurface,
138+
title: const Column(
139+
crossAxisAlignment: CrossAxisAlignment.start,
140+
children: <Widget>[
141+
Text('enabled: false'),
142+
Text('requestFocusOnTap: false'),
143+
],
144+
),
145+
subtitle: Column(
146+
children: <Widget>[
147+
DropdownMenu<String>(
148+
enabled: false,
149+
requestFocusOnTap: false,
150+
initialSelection: list.first,
151+
expandedInsets: EdgeInsets.zero,
152+
onSelected: (String? value) {
153+
setState(() {
154+
dropdownValue = value!;
155+
});
156+
},
157+
dropdownMenuEntries:
158+
list.map<DropdownMenuEntry<String>>((String value) {
159+
return DropdownMenuEntry<String>(value: value, label: value);
160+
}).toList(),
161+
),
162+
const Text('Default cursor is shown when hovering over the DropdownMenu.'),
163+
],
164+
),
165+
),
166+
],
167+
);
168+
}
169+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Copyright 2014 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'dart:ui';
6+
7+
import 'package:flutter/material.dart';
8+
import 'package:flutter/rendering.dart';
9+
import 'package:flutter_api_samples/material/dropdown_menu/dropdown_menu.2.dart' as example;
10+
import 'package:flutter_test/flutter_test.dart';
11+
12+
void main() {
13+
testWidgets('DropdownMenu cursor behavoir', (WidgetTester tester) async {
14+
await tester.pumpWidget(
15+
const example.DropdownMenuApp(),
16+
);
17+
18+
Finder textFieldFinder(int index) {
19+
return find.byType(TextField).at(index);
20+
}
21+
22+
// Hover over the "enabled and requestFocusOnTap set to true" text field.
23+
final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse, pointer: 1);
24+
await gesture.moveTo(tester.getCenter(textFieldFinder(0)));
25+
26+
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.text);
27+
28+
// Hover over the "enabled and requestFocusOnTap set to false" text field.
29+
await gesture.moveTo(tester.getCenter(textFieldFinder(1)));
30+
31+
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.click);
32+
33+
// Hover over the "disabled and requestFocusOnTap set to true" text field.
34+
await gesture.moveTo(tester.getCenter(textFieldFinder(2)));
35+
36+
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic);
37+
38+
// Hover over the "disabled and requestFocusOnTap set to false" text field.
39+
await gesture.moveTo(tester.getCenter(textFieldFinder(3)));
40+
41+
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic);
42+
});
43+
}

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,13 @@ class DropdownMenu<T> extends StatefulWidget {
170170
/// Determine if the [DropdownMenu] is enabled.
171171
///
172172
/// Defaults to true.
173+
///
174+
/// {@tool dartpad}
175+
/// This sample demonstrates how the [enabled] and [requestFocusOnTap] properties
176+
/// affect the textfield's hover cursor.
177+
///
178+
/// ** See code in examples/api/lib/material/dropdown_menu/dropdown_menu.2.dart **
179+
/// {@end-tool}
173180
final bool enabled;
174181

175182
/// Determine the width of the [DropdownMenu].
@@ -338,6 +345,13 @@ class DropdownMenu<T> extends StatefulWidget {
338345
/// focus when activated.
339346
///
340347
/// Set this to true or false explicitly to override the default behavior.
348+
///
349+
/// {@tool dartpad}
350+
/// This sample demonstrates how the [enabled] and [requestFocusOnTap] properties
351+
/// affect the textfield's hover cursor.
352+
///
353+
/// ** See code in examples/api/lib/material/dropdown_menu/dropdown_menu.2.dart **
354+
/// {@end-tool}
341355
final bool? requestFocusOnTap;
342356

343357
/// Descriptions of the menu items in the [DropdownMenu].

0 commit comments

Comments
 (0)