Add DropdownMenu cursor behavior sample (#146133)

fixes [Add `DropdownMenu` cursor behavior sample to  `DropdownMenu.enabled` & `DropdownMenu.requestFocusOnTap`  docs](https://github.com/flutter/flutter/issues/146131)

### Preview
![Screenshot 2024-04-02 at 17 12 43](https://github.com/flutter/flutter/assets/48603081/33865ca0-d48d-4651-9c83-9bdcd6369cb8)
This commit is contained in:
Taha Tesser
2024-04-03 19:31:06 +03:00
committed by GitHub
parent e868e2b383
commit 80d774d8dc
3 changed files with 226 additions and 0 deletions

View File

@@ -0,0 +1,169 @@
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/material.dart';
/// Flutter code sample for [DropdownMenu].
const List<String> list = <String>['One', 'Two', 'Three', 'Four'];
void main() => runApp(const DropdownMenuApp());
class DropdownMenuApp extends StatelessWidget {
const DropdownMenuApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text('DropdownMenu Sample')),
body: const Center(
child: DropdownMenuExample(),
),
),
);
}
}
class DropdownMenuExample extends StatefulWidget {
const DropdownMenuExample({super.key});
@override
State<DropdownMenuExample> createState() => _DropdownMenuExampleState();
}
class _DropdownMenuExampleState extends State<DropdownMenuExample> {
String dropdownValue = list.first;
@override
Widget build(BuildContext context) {
final ColorScheme colorScheme = Theme.of(context).colorScheme;
return ListView(
children: <Widget>[
ListTile(
tileColor: colorScheme.primaryContainer,
title: const Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text('enabled: true'),
Text('requestFocusOnTap: true'),
],
),
subtitle: Column(
children: <Widget>[
DropdownMenu<String>(
requestFocusOnTap: true,
initialSelection: list.first,
expandedInsets: EdgeInsets.zero,
onSelected: (String? value) {
setState(() {
dropdownValue = value!;
});
},
dropdownMenuEntries:
list.map<DropdownMenuEntry<String>>((String value) {
return DropdownMenuEntry<String>(value: value, label: value);
}).toList(),
),
const Text('Text cursor is shown when hovering over the DropdownMenu.'),
],
),
),
const SizedBox(height: 20),
ListTile(
tileColor: colorScheme.primaryContainer,
title: const Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text('enabled: true'),
Text('requestFocusOnTap: false'),
],
),
subtitle: Column(
children: <Widget>[
DropdownMenu<String>(
requestFocusOnTap: false,
initialSelection: list.first,
expandedInsets: EdgeInsets.zero,
onSelected: (String? value) {
setState(() {
dropdownValue = value!;
});
},
dropdownMenuEntries:
list.map<DropdownMenuEntry<String>>((String value) {
return DropdownMenuEntry<String>(value: value, label: value);
}).toList(),
),
const Text('Clickable cursor is shown when hovering over the DropdownMenu.'),
],
),
),
const SizedBox(height: 20),
ListTile(
tileColor: colorScheme.onInverseSurface,
title: const Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text('enabled: false'),
Text('requestFocusOnTap: true'),
],
),
subtitle: Column(
children: <Widget>[
DropdownMenu<String>(
enabled: false,
requestFocusOnTap: true,
initialSelection: list.first,
expandedInsets: EdgeInsets.zero,
onSelected: (String? value) {
setState(() {
dropdownValue = value!;
});
},
dropdownMenuEntries:
list.map<DropdownMenuEntry<String>>((String value) {
return DropdownMenuEntry<String>(value: value, label: value);
}).toList(),
),
const Text('Default cursor is shown when hovering over the DropdownMenu.'),
],
),
),
const SizedBox(height: 20),
ListTile(
tileColor: colorScheme.onInverseSurface,
title: const Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text('enabled: false'),
Text('requestFocusOnTap: false'),
],
),
subtitle: Column(
children: <Widget>[
DropdownMenu<String>(
enabled: false,
requestFocusOnTap: false,
initialSelection: list.first,
expandedInsets: EdgeInsets.zero,
onSelected: (String? value) {
setState(() {
dropdownValue = value!;
});
},
dropdownMenuEntries:
list.map<DropdownMenuEntry<String>>((String value) {
return DropdownMenuEntry<String>(value: value, label: value);
}).toList(),
),
const Text('Default cursor is shown when hovering over the DropdownMenu.'),
],
),
),
],
);
}
}

View File

@@ -0,0 +1,43 @@
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_api_samples/material/dropdown_menu/dropdown_menu.2.dart' as example;
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('DropdownMenu cursor behavoir', (WidgetTester tester) async {
await tester.pumpWidget(
const example.DropdownMenuApp(),
);
Finder textFieldFinder(int index) {
return find.byType(TextField).at(index);
}
// Hover over the "enabled and requestFocusOnTap set to true" text field.
final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse, pointer: 1);
await gesture.moveTo(tester.getCenter(textFieldFinder(0)));
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.text);
// Hover over the "enabled and requestFocusOnTap set to false" text field.
await gesture.moveTo(tester.getCenter(textFieldFinder(1)));
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.click);
// Hover over the "disabled and requestFocusOnTap set to true" text field.
await gesture.moveTo(tester.getCenter(textFieldFinder(2)));
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic);
// Hover over the "disabled and requestFocusOnTap set to false" text field.
await gesture.moveTo(tester.getCenter(textFieldFinder(3)));
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic);
});
}

View File

@@ -170,6 +170,13 @@ class DropdownMenu<T> extends StatefulWidget {
/// Determine if the [DropdownMenu] is enabled.
///
/// Defaults to true.
///
/// {@tool dartpad}
/// This sample demonstrates how the [enabled] and [requestFocusOnTap] properties
/// affect the textfield's hover cursor.
///
/// ** See code in examples/api/lib/material/dropdown_menu/dropdown_menu.2.dart **
/// {@end-tool}
final bool enabled;
/// Determine the width of the [DropdownMenu].
@@ -338,6 +345,13 @@ class DropdownMenu<T> extends StatefulWidget {
/// focus when activated.
///
/// Set this to true or false explicitly to override the default behavior.
///
/// {@tool dartpad}
/// This sample demonstrates how the [enabled] and [requestFocusOnTap] properties
/// affect the textfield's hover cursor.
///
/// ** See code in examples/api/lib/material/dropdown_menu/dropdown_menu.2.dart **
/// {@end-tool}
final bool? requestFocusOnTap;
/// Descriptions of the menu items in the [DropdownMenu].