-
Notifications
You must be signed in to change notification settings - Fork 28.6k
DropdownMenuItem does not support use GlobalKey #80200
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
@braxtonmckee
(source) may I ask what this implementation is meant to accomplish and why needs to use |
This is a minimal repro of a bug that I encountered building a larger app.
If you had state inside of a dropdown item that you wanted to maintain, how
else would you do it?
Finally: given the semantics of the 'GlobalKey', I certainly wouldn't
expect this to blow up, as the widget is not actually being used twice in
the tree. I would think that as long as you maintain the invariant that
you're not using a GlobalKey more than once in a widget tree, you shouldn't
be penalized for using them.
…On Sat, Apr 10, 2021 at 4:15 PM Francesco Iapicca ***@***.***> wrote:
@braxtonmckee <https://github.com/braxtonmckee>
I suspect that global keys aren't meant to be used this way especially
- not to be "moved in the widget tree" paraphrasing the error [...]
the previous instance is moved to the new location
- to be used for a State
- not to be instantiated inside the build method
a good practice is to let a State object own the GlobalKey, and
instantiate it outside the build method
(source <https://api.flutter.dev/flutter/widgets/GlobalKey-class.html>)
may I ask what this implementation is meant to accomplish and why needs to
use GlobalKey?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#80200 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AB6OHBB2OBNRRUWMF3EAUKLTICWW7ANCNFSM42WYZUBQ>
.
|
Hi @braxtonmckee flutter doctor -v[✓] Flutter (Channel stable, 2.0.4, on Microsoft Windows [Version 10.0.19042.870], locale en-US)
• Flutter version 2.0.4 at C:\Users\Taha\Code\flutter_stable
• Framework revision b1395592de (11 days ago), 2021-04-01 14:25:01 -0700
• Engine revision 2dce47073a
• Dart version 2.12.2
[!] Android toolchain - develop for Android devices (Android SDK version 30.0.3)
• Android SDK at C:\Users\Taha\Code\SDK
• Platform android-30, build-tools 30.0.3
• ANDROID_HOME = C:\Users\Taha\Code\SDK
• Java binary at: C:\Users\Taha\Code\android-studio\jre\bin\java
• Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b01)
✗ Android license status unknown.
Run `flutter doctor --android-licenses` to accept the SDK licenses.
See https://flutter.dev/docs/get-started/install/windows#android-setup for more details.
[✓] Chrome - develop for the web
• Chrome at C:\Program Files\Google\Chrome\Application\chrome.exe
[✓] Visual Studio - develop for Windows (Visual Studio Community 2019 16.9.2)
• Visual Studio at C:\Program Files (x86)\Microsoft Visual Studio\2019\Community
• Visual Studio Community 2019 version 16.9.31112.23
• Windows 10 SDK version 10.0.19041.0
[✓] Android Studio (version 4.1.0)
• Android Studio at C:\Users\Taha\Code\android-studio
• Flutter plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/9212-flutter
• Dart plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/6351-dart
• Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b01)
[✓] IntelliJ IDEA Community Edition (version 2021.1)
• IntelliJ at C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2020.3.3
• Flutter plugin version 55.0.5
• Dart plugin version 211.6693.108
[✓] VS Code (version 1.55.1)
• VS Code at C:\Users\Taha\AppData\Local\Programs\Microsoft VS Code
• Flutter extension version 3.21.0
[✓] Connected device (4 available)
• RMX2001 (mobile) • EUYTFEUSQSRGDA6D • android-arm64 • Android 10 (API 29)
• Windows (desktop) • windows • windows-x64 • Microsoft Windows [Version 10.0.19042.870]
• Chrome (web) • chrome • web-javascript • Google Chrome 89.0.4389.114
• Edge (web) • edge • web-javascript • Microsoft Edge 89.0.774.68
! Doctor found issues in 1 category. [✓] Flutter (Channel master, 2.1.0-13.0.pre.574, on Microsoft Windows [Version 10.0.19042.870], locale en-US)
• Flutter version 2.1.0-13.0.pre.574 at C:\Users\Taha\Code\flutter_master
• Framework revision 02efffc134 (2 days ago), 2021-04-10 03:49:01 -0400
• Engine revision 8863afff16
• Dart version 2.13.0 (build 2.13.0-222.0.dev)
[!] Android toolchain - develop for Android devices (Android SDK version 30.0.3)
• Android SDK at C:\Users\Taha\Code\SDK
• Platform android-30, build-tools 30.0.3
• ANDROID_HOME = C:\Users\Taha\Code\SDK
• Java binary at: C:\Users\Taha\Code\android-studio\jre\bin\java
• Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b01)
✗ Android license status unknown.
Run `flutter doctor --android-licenses` to accept the SDK licenses.
See https://flutter.dev/docs/get-started/install/windows#android-setup for more details.
[✓] Chrome - develop for the web
• Chrome at C:\Program Files\Google\Chrome\Application\chrome.exe
[✓] Visual Studio - develop for Windows (Visual Studio Community 2019 16.9.2)
• Visual Studio at C:\Program Files (x86)\Microsoft Visual Studio\2019\Community
• Visual Studio Community 2019 version 16.9.31112.23
• Windows 10 SDK version 10.0.19041.0
[✓] Android Studio (version 4.1.0)
• Android Studio at C:\Users\Taha\Code\android-studio
• Flutter plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/9212-flutter
• Dart plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/6351-dart
• Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b01)
[✓] IntelliJ IDEA Community Edition (version 2021.1)
• IntelliJ at C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2020.3.3
• Flutter plugin version 55.0.5
• Dart plugin version 211.6693.108
[✓] VS Code (version 1.55.1)
• VS Code at C:\Users\Taha\AppData\Local\Programs\Microsoft VS Code
• Flutter extension version 3.21.0
[✓] Connected device (4 available)
• RMX2001 (mobile) • EUYTFEUSQSRGDA6D • android-arm64 • Android 10 (API 29)
• Windows (desktop) • windows • windows-x64 • Microsoft Windows [Version 10.0.19042.870]
• Chrome (web) • chrome • web-javascript • Google Chrome 89.0.4389.114
• Edge (web) • edge • web-javascript • Microsoft Edge 89.0.774.68
! Doctor found issues in 1 category. |
Can you elaborate on what state are you trying to preserve? Also, if you look into the widget tree when the |
Hi @werainkhatri, Thanks for getting back to me. This is a minimal repro, so maybe it seems contrived, but I'm happy to provide some context if it helps motivate the issue. In my application, I have a tree of UI widgets that get populated over a socket connection (this is a remote desktop application). I'm mirroring this tree into the widget tree. The GlobalKey abstraction should make it possible for me maintain a 1-1 correspondence between flutter widgets and nodes in my tree as identified by my server. This is perfect for my use case, since that's exactly how my remoting protocol works. Every node in the tree has a unique identity, and each change to the tree on the server side sends a message to me giving the identity of the changed node and the change itself. For instance, if a list-view sees its items reordered, I'll receive an update list of ordered child identities. This should be a perfect analogy to the GlobalKey model: I simply reorder the children in the widget, all of which are identified by GlobalKey objects, and then the rendering layer can reorder them without needing to rebuild the entire tree or destroy the ui state. For most widgets this works great. Except I'm finding some widgets complain (as is the case with the DropdownButton) if any widget inside of them has a GlobalKey because they expect that their children are "simple" and don't have GlobalKeys inside. Looking at the tree above, to me it feels like the widgets should only show up in one place in the tree at once since they're only visible in one place at once on the screen. If the point of the MaterialApp is to provide a layer to host animations and popovers, then why do the menu item widgets also need to show up underneath the DropdownButton object in the tree? In any case, I suppose I could imagine that some widgets expect their children to be stateless, and cannot accept globally keyed widgets or something, but then that should be documented. But really it just seems like a bug that the widget is in the tree twice. After all, my build method only got called once, which means the DropdownMenuItem objects were only called once, and yet they are showing up in two separate places in the tree. Anyways, thanks again for looking at this. --braxton |
When the button is opened, the item will attach to two different subtrees at the same time, so if the item or its descendants have a GlobalKey, an assertion will be triggered. Sample Code/// Flutter code sample for DropdownButton
// This sample shows a `DropdownButton` with a large arrow icon,
// purple text style, and bold purple underline, whose value is one of "One",
// "Two", "Free", or "Four".
//
// 
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
/// This is the main application widget.
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
static const String _title = 'Flutter Code Sample';
@override
Widget build(BuildContext context) {
return MaterialApp(
title: _title,
home: Scaffold(
appBar: AppBar(title: const Text(_title)),
body: const Center(
child: MyStatefulWidget(),
),
),
);
}
}
/// This is the stateful widget that the main application instantiates.
class MyStatefulWidget extends StatefulWidget {
const MyStatefulWidget({Key? key}) : super(key: key);
@override
_MyStatefulWidgetState createState() => _MyStatefulWidgetState();
}
/// This is the private State class that goes with MyStatefulWidget.
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
String dropdownValue = 'One';
GlobalKey _key = GlobalKey();
@override
Widget build(BuildContext context) {
return DropdownButton<String>(
value: dropdownValue,
icon: const Icon(Icons.arrow_downward),
iconSize: 24,
elevation: 16,
style: const TextStyle(color: Colors.deepPurple),
underline: Container(
height: 2,
color: Colors.deepPurpleAccent,
),
onChanged: (String? newValue) {
setState(() {
dropdownValue = newValue!;
});
},
items: <String>['One', 'Two', 'Free', 'Four']
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
key: (value == 'One') ? _key : null,
value: value,
child: Text(value),
);
}).toList(),
);
}
}
|
@xu-baolin It's unfortunate because we end up using the passed in |
That sounds like something we should not do. Do you know why we do that? |
I think it's because the widget styling for both the button and the dropdown menu item are identical in the default scenario, so |
Here's a WIP proof of concept that fixes the GlobalKey issue: #81878. Tested this with the code sample that @xu-baolin provided that reproduces the problem, and no errors pop up. It basically just removes the usage of The only thing that's missing is how we'd provide keys to the menu items in the Edit: Never mind, it seems like this approach is a breaking change because there are behaviors that rely on the usage of keys for the dropdown menu items. I also suspect this would break a whole bunch of user code |
Here's an idea. Can we remove the items from the Series of events will be - The only problem I think this will have is performance and possibly UX issues. |
The problem with that approach is that |
Uh oh!
There was an error while loading. Please reload this page.
I'm getting exceptions when using widgets that contain GlobalKeys inside of some widgets, in particular DropdownButton. Am I using it wrong? Based on what I have found on the web, this appears to be the way its supposed to be used.
Here's a simple repro:
code sample
Steps to Reproduce
Run the app and click the dropdown. You'll see an exception thrown internally.
Expected results:
It not throwing exceptions.
Actual results:
It throws exceptions.
flutter doctor
The text was updated successfully, but these errors were encountered: