Skip to content
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

DropdownMenu experiences screen jitter issues when used within TabBarView alongside nested navigation #139113

Open
2 tasks done
hiepvip99 opened this issue Nov 28, 2023 · 12 comments
Assignees
Labels
f: material design flutter/packages/flutter/material repository. found in release: 3.16 Found to occur in 3.16 found in release: 3.17 Found to occur in 3.17 framework flutter/packages/flutter repository. See also f: labels. has reproducible steps The issue has been confirmed reproducible and is ready to work on Bot is counting down the days until it unassigns the issue team-design Owned by Design Languages team

Comments

@hiepvip99
Copy link

Is there an existing issue for this?

Steps to reproduce

"Step 1: Create a tab bar with nested navigation inside.
Step 2: Create a sub-route and use DropdownMenu on that route."

Expected results

After changing the data and clicking on it again, the DropdownMenu will not experience screen jitter

Actual results

After changing the data and clicking on it again, the DropdownMenu will experience screen jitter

Code sample

Code sample
import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> with TickerProviderStateMixin {
  late TabController _tabController;

  @override
  void initState() {
    super.initState();
    _tabController = TabController(length: 2, vsync: this);
  }

  @override
  void dispose() {
    _tabController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Nested TabBar Example'),
        bottom: TabBar(
          tabs: [
            Tab(text: 'Tab 1'),
            Tab(text: 'Tab 2'),
          ],
          controller: _tabController,
        ),
      ),
      body: TabBarView(
        controller: _tabController,
        children: [
          FirstTabScreen(),
          SecondTabScreen(),
        ],
      ),
    );
  }
}

class FirstTabScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Navigator(
      onGenerateRoute: (settings) {
        return MaterialPageRoute(
          builder: (context) => FirstTabContentScreen(),
        );
      },
    );
  }
}

class FirstTabContentScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('First Tab Content'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text('Content for First Tab'),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: () {
                Navigator.push(
                  context,
                  MaterialPageRoute(
                    builder: (context) => FirstTabChildScreen(),
                  ),
                );
              },
              child: Text('Go to Child Screen'),
            ),
          ],
        ),
      ),
    );
  }
}

class FirstTabChildScreen extends StatefulWidget {
  @override
  State<FirstTabChildScreen> createState() => _FirstTabChildScreenState();
}

const List<String> list = <String>['One', 'Two', 'Three', 'Four'];

class _FirstTabChildScreenState extends State<FirstTabChildScreen> {
  String dropdownValue = list.first;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('First Tab Child Screen'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text('Content for First Tab Child Screen'),
            SizedBox(height: 20),
            DropdownButton<String>(
              value: dropdownValue,
              icon: const Icon(Icons.arrow_downward),
              elevation: 16,
              style: const TextStyle(color: Colors.deepPurple),
              underline: Container(
                height: 2,
                color: Colors.deepPurpleAccent,
              ),
              onChanged: (String? value) {
                // This is called when the user selects an item.
                setState(() {
                  dropdownValue = value!;
                });
              },
              items: list.map<DropdownMenuItem<String>>((String value) {
                return DropdownMenuItem<String>(
                  value: value,
                  child: Text(value),
                );
              }).toList(),
            ),
            ElevatedButton(
              onPressed: () {
                Navigator.pop(context); // Go back to the parent screen
              },
              child: Text('Go Back'),
            ),
          ],
        ),
      ),
    );
  }
}

class SecondTabScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Navigator(
      onGenerateRoute: (settings) {
        return MaterialPageRoute(
          builder: (context) => Scaffold(
            appBar: AppBar(
              title: Text('Second Tab'),
            ),
            body: Center(
              child: Text('Content for Second Tab'),
            ),
          ),
        );
      },
    );
  }
}

Screenshots or Video

Screenshots / Video demonstration

[Upload media here]

Logs

Logs
[Paste your logs here]

Flutter Doctor output

Doctor output
Doctor summary (to see all details, run flutter doctor -v):
[√] Flutter (Channel stable, 3.16.0, on Microsoft Windows [Version 10.0.19045.3693], locale en-US)
[√] Windows Version (Installed version of Windows is version 10 or higher)
[!] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
    X 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.
[X] Chrome - develop for the web (Cannot find Chrome executable at .\Google\Chrome\Application\chrome.exe)
    ! Cannot find Chrome. Try setting CHROME_EXECUTABLE to a Chrome executable.
[√] Visual Studio - develop Windows apps (Visual Studio Community 2022 17.6.5)
[√] Android Studio (version 2022.2)
[√] VS Code (version 1.84.2)
[√] Connected device (3 available)
[√] Network resources

! Doctor found issues in 2 categories.
@huycozy huycozy added the in triage Presently being triaged by the triage team label Nov 28, 2023
@huycozy
Copy link
Member

huycozy commented Nov 28, 2023

Hi @hiepvip99
I checked this on Realme 6, Android 11 but can't see the issue.

Which platform are you checking on? And please also share the device information as well (OS, model). It would be useful if you could share a recorded video demo for this. Thanks!

@huycozy huycozy added the waiting for customer response The Flutter team cannot make further progress on this issue until the original reporter responds label Nov 28, 2023
@hiepvip99
Copy link
Author

I apologize for this confusion as I tried DropdownButton and DropdownMenu, and the issue only occurred in DropdownMenu. You can test it with this code snippet (This issue occurs on both Android, Web and iOS.): @huycozy

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> with TickerProviderStateMixin {
  late TabController _tabController;

  @override
  void initState() {
    super.initState();
    _tabController = TabController(length: 2, vsync: this);
  }

  @override
  void dispose() {
    _tabController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Nested TabBar Example'),
        bottom: TabBar(
          tabs: [
            Tab(text: 'Tab 1'),
            Tab(text: 'Tab 2'),
          ],
          controller: _tabController,
        ),
      ),
      body: TabBarView(
        controller: _tabController,
        children: [
          FirstTabScreen(),
          SecondTabScreen(),
        ],
      ),
    );
  }
}

class FirstTabScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Navigator(
      onGenerateRoute: (settings) {
        return MaterialPageRoute(
          builder: (context) => FirstTabContentScreen(),
        );
      },
    );
  }
}

class FirstTabContentScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('First Tab Content'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text('Content for First Tab'),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: () {
                Navigator.push(
                  context,
                  MaterialPageRoute(
                    builder: (context) => FirstTabChildScreen(),
                  ),
                );
              },
              child: Text('Go to Child Screen'),
            ),
          ],
        ),
      ),
    );
  }
}

class FirstTabChildScreen extends StatefulWidget {
  @override
  State<FirstTabChildScreen> createState() => _FirstTabChildScreenState();
}

const List<String> list = <String>['One', 'Two', 'Three', 'Four'];

class _FirstTabChildScreenState extends State<FirstTabChildScreen> {
  String dropdownValue = list.first;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('First Tab Child Screen'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text('Content for First Tab Child Screen'),
            SizedBox(height: 20),
            DropdownMenu<String>(
              initialSelection: list.first,
              // controller: colorController,
              // requestFocusOnTap is enabled/disabled by platforms when it is null.
              // On mobile platforms, this is false by default. Setting this to true will
              // trigger focus request on the text field and virtual keyboard will appear
              // afterward. On desktop platforms however, this defaults to true.
              requestFocusOnTap: true,
              // label: const Text('Color'),
              onSelected: (String? v) {
                setState(() {
                  if (v != null) {
                    dropdownValue = v;
                  }
                });
              },
              dropdownMenuEntries:
                  list.map<DropdownMenuEntry<String>>((String color) {
                return DropdownMenuEntry<String>(
                  value: color,
                  label: color,
                  enabled: true,
                  // style: MenuItemButton.styleFrom(
                  //   foregroundColor: color.color,
                  // ),
                );
              }).toList(),
            ),
            ElevatedButton(
              onPressed: () {
                Navigator.pop(context); // Go back to the parent screen
              },
              child: Text('Go Back'),
            ),
          ],
        ),
      ),
    );
  }
}

class SecondTabScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Navigator(
      onGenerateRoute: (settings) {
        return MaterialPageRoute(
          builder: (context) => Scaffold(
            appBar: AppBar(
              title: Text('Second Tab'),
            ),
            body: Center(
              child: Text('Content for Second Tab'),
            ),
          ),
        );
      },
    );
  }
}

@github-actions github-actions bot removed the waiting for customer response The Flutter team cannot make further progress on this issue until the original reporter responds label Nov 29, 2023
@hiepvip99
Copy link
Author

hiepvip99 commented Nov 29, 2023

@huycozy
Copy link
Member

huycozy commented Nov 29, 2023

Thanks for the updated sample code with DropdownMenu. Reproduced this issue on the latest Flutter channel (stable/master); it also appears on the previous release 3.13.9.

flutter doctor -v (stable and master)
[✓] Flutter (Channel stable, 3.16.1, on macOS 14.1 23B74 darwin-x64, locale en-VN)
    • Flutter version 3.16.1 on channel stable at /Users/huynq/Documents/GitHub/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 7f20e5d18c (9 hours ago), 2023-11-27 09:47:30 -0800
    • Engine revision 22b600f240
    • Dart version 3.2.1
    • DevTools version 2.28.3

[✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
    • Android SDK at /Users/huynq/Library/Android/sdk
    • Platform android-34, build-tools 34.0.0
    • ANDROID_HOME = /Users/huynq/Library/Android/sdk
    • Java binary at: /Applications/Android Studio.app/Contents/jbr/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 17.0.6+0-17.0.6b802.4-9586694)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 15.0.1)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Build 15A507
    • CocoaPods version 1.13.0

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[!] Android Studio (version unknown)
    • Android Studio at /Applications/Android Studio Preview.app/Contents
    • 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
    ✗ Unable to determine Android Studio version.
    • Java version OpenJDK Runtime Environment (build 17.0.8+0-17.0.8b1000.22-10799086)

[✓] Android Studio (version 2022.3)
    • Android Studio at /Applications/Android Studio Giraffe Patch 3.app/Contents
    • 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 17.0.6+0-17.0.6b829.9-10027231)

[✓] Android Studio (version 2022.2)
    • Android Studio at /Applications/Android Studio.app/Contents
    • 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
    • android-studio-dir = /Applications/Android Studio.app/
    • Java version OpenJDK Runtime Environment (build 17.0.6+0-17.0.6b802.4-9586694)

[✓] VS Code (version 1.84.2)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.76.0

[✓] Connected device (3 available)
    • RMX2001 (mobile) • EUYTFEUSQSRGDA6D • android-arm64  • Android 11 (API 30)
    • macOS (desktop)  • macos            • darwin-x64     • macOS 14.1 23B74 darwin-x64
    • Chrome (web)     • chrome           • web-javascript • Google Chrome 119.0.6045.159

[✓] Network resources
    • All expected network resources are available.

! Doctor found issues in 1 category.
[!] Flutter (Channel master, 3.17.0-17.0.pre.47, on macOS 14.1 23B74 darwin-x64, locale en-VN)
    • Flutter version 3.17.0-17.0.pre.47 on channel master at /Users/huynq/Documents/GitHub/flutter_master
    ! Warning: `flutter` on your path resolves to /Users/huynq/Documents/GitHub/flutter/bin/flutter, which is not inside your current Flutter SDK checkout at /Users/huynq/Documents/GitHub/flutter_master. Consider adding /Users/huynq/Documents/GitHub/flutter_master/bin to the front of your path.
    ! Warning: `dart` on your path resolves to /Users/huynq/Documents/GitHub/flutter/bin/dart, which is not inside your current Flutter SDK checkout at /Users/huynq/Documents/GitHub/flutter_master. Consider adding /Users/huynq/Documents/GitHub/flutter_master/bin to the front of your path.
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 7a0508e5de (10 minutes ago), 2023-11-28 22:01:04 -0500
    • Engine revision 4beaa1195b
    • Dart version 3.3.0 (build 3.3.0-170.0.dev)
    • DevTools version 2.30.0-dev.4
    • If those were intentional, you can disregard the above warnings; however it is recommended to use "git" directly to perform update checks and upgrades.

[✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
    • Android SDK at /Users/huynq/Library/Android/sdk
    • Platform android-34, build-tools 34.0.0
    • ANDROID_HOME = /Users/huynq/Library/Android/sdk
    • Java binary at: /Applications/Android Studio.app/Contents/jbr/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 17.0.6+0-17.0.6b802.4-9586694)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 15.0.1)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Build 15A507
    • CocoaPods version 1.13.0

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[!] Android Studio (version unknown)
    • Android Studio at /Applications/Android Studio Preview.app/Contents
    • 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
    ✗ Unable to determine Android Studio version.
    • Java version OpenJDK Runtime Environment (build 17.0.8+0-17.0.8b1000.22-10799086)

[✓] Android Studio (version 2022.3)
    • Android Studio at /Applications/Android Studio Giraffe Patch 3.app/Contents
    • 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 17.0.6+0-17.0.6b829.9-10027231)

[✓] Android Studio (version 2022.2)
    • Android Studio at /Applications/Android Studio.app/Contents
    • 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
    • android-studio-dir = /Applications/Android Studio.app/
    • Java version OpenJDK Runtime Environment (build 17.0.6+0-17.0.6b802.4-9586694)

[✓] VS Code (version 1.84.2)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.76.0

[✓] Connected device (4 available)
    • RMX2001 (mobile) • EUYTFEUSQSRGDA6D                         • android-arm64  • Android 11 (API 30)
    • iPhone (mobile)  • d9a94afe2b649fef56ba0bfeb052f0f2a7dae95e • ios            • iOS 15.8 19H370
    • macOS (desktop)  • macos                                    • darwin-x64     • macOS 14.1 23B74 darwin-x64
    • Chrome (web)     • chrome                                   • web-javascript • Google Chrome 119.0.6045.159

[✓] Network resources
    • All expected network resources are available.

! Doctor found issues in 2 categories.

@huycozy huycozy added framework flutter/packages/flutter repository. See also f: labels. f: material design flutter/packages/flutter/material repository. has reproducible steps The issue has been confirmed reproducible and is ready to work on team-design Owned by Design Languages team found in release: 3.16 Found to occur in 3.16 found in release: 3.17 Found to occur in 3.17 and removed in triage Presently being triaged by the triage team labels Nov 29, 2023
@QuncCccccc
Copy link
Contributor

Thanks for filing this issue! Looks like this problem happens when search is enabled, and then ensureVisible() is called to scroll to the matching menu item. I'm still investigating the root cause. As a workaround for now, setting enabledSearch to false will stop the tab view scrolling.

@iaTuaD
Copy link

iaTuaD commented Nov 30, 2023

Another problem occurs when setting the enableSearch: false property,
The problem is that when selecting an item in the menu and when reopening the menu, the selected item in the menu is not highlighted, please help me.
Screenshot 2023-11-30 at 10 39 50
@QuncCccccc

@QuncCccccc
Copy link
Contributor

Yes...the matching item is highlighted only when enableSearch is set to true. Sorry for the inconvenience.

@sashkent3
Copy link

I'm experiencing a very similar issue. Here's a minimal example on dartpad.dev. In my case, it's even possible to switch tabs (from 'Tab 2' to 'Tab 3') upon opening the dropdown.

@hiepvip99
Copy link
Author

@sashkent3 It seems like they are not concerned about fixing this bug, it's been a few months already and I haven't seen any progress on it.

@flutter-triage-bot flutter-triage-bot bot added the Bot is counting down the days until it unassigns the issue label Apr 4, 2024
@flutter-triage-bot
Copy link

This issue is assigned to @QuncCccccc but has had no recent status updates. Please consider unassigning this issue if it is not going to be addressed in the near future. This allows people to have a clearer picture of what work is actually planned. Thanks!

@EveNaari
Copy link

EveNaari commented Apr 4, 2024

Same issue here. Any news about fixing it? Maybe you need more info?

@Yukinosuke-Takada
Copy link

I also noticed this issue after upgrading Flutter. I did a little digging but couldn't find what's causing this. But here's what I could get.

The minimum example:

import 'package:flutter/material.dart';

void main() {
  // run(mode: RunMode.development);

  runApp(
    const MaterialApp(
      home: SamplePage(),
    ),
  );
}

class SamplePage extends StatelessWidget {
  const SamplePage({super.key});

  @override
  Widget build(BuildContext context) {
    return DefaultTabController(
      length: 2,
      child: Scaffold(
        appBar: AppBar(
          title: const Text('App Bar Title'),
          bottom: const TabBar(
            tabs: [
              Tab(text: 'Tab 1'),
              Tab(text: 'Tab 2'),
            ],
          ),
        ),
        body: TabBarView(
          children: [
            Container(
              width: double.infinity,
              height: double.infinity,
              color: Colors.red[100],
              child: const Padding(
                padding: EdgeInsets.only(left: 160),
                child: SingleChildScrollView(
                  child: DropdownMenu(
                    dropdownMenuEntries: [
                      DropdownMenuEntry(
                        label: 'Option 1',
                        value: '1',
                      ),
                      DropdownMenuEntry(
                        label: 'Option 2',
                        value: '2',
                      ),
                    ],
                  ),
                ),
              ),
            ),
            Container(
              width: double.infinity,
              height: double.infinity,
              color: Colors.blue[100],
              child: Text('Tab 2'),
            ),
          ],
        ),
      ),
    );
  }
}

v3.16.8 works as expected.

Simulator.Screen.Recording.-.iPhone.15.Pro.Max.-.2024-05-05.at.15.15.25.mp4

v3.19.6 (current stable) has issue.

Simulator.Screen.Recording.-.iPhone.15.Pro.Max.-.2024-05-05.at.15.26.46.mp4

The jittering gets worse the more complex the widget is and at some point, you can't select the entries anymore.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
f: material design flutter/packages/flutter/material repository. found in release: 3.16 Found to occur in 3.16 found in release: 3.17 Found to occur in 3.17 framework flutter/packages/flutter repository. See also f: labels. has reproducible steps The issue has been confirmed reproducible and is ready to work on Bot is counting down the days until it unassigns the issue team-design Owned by Design Languages team
Projects
None yet
Development

No branches or pull requests

7 participants