Carlos Costa
Carlos Costa

Reputation: 197

DropdowMenu does not show the selected Item

In the following code i can add and remove Tabs to the screen. For removing, i have defide a Button on the AppBar that after pressing it a DropdownMenu appears who let me select which Tab i want to remove and it removes the selected Item. The problem that i have is that when i select a item DropdownMenu it does not show the selected item.

Thanks in advance for some help.

Follows the complete code:

import 'package:flutter/material.dart';

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

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

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Home(),
    );
  }
}

class Home extends StatefulWidget {
  const Home({super.key});

  @override
  HomeState createState() => HomeState();
}

class HomeState extends State<Home> {
  String? selectedTab = tabs[0].text;
  var tabName = "";

  static List<Tab> tabs = [
    const Tab(text: ""),
  ];

  List<Widget> tabViewChildren = [
    Container(
      height: 400,
    ),
  ];

  @override
  Widget build(BuildContext context) {
    return DefaultTabController(
        initialIndex: 0,
        length: tabs.length,
        child: Scaffold(
            appBar: AppBar(
              actions: <Widget>[
                ElevatedButton.icon(
                  onPressed: () {
                    showDialog(
                      context: context,
                      builder: (BuildContext context) {
                        return AlertDialog(
                          title: const Text("Enter tab name"),
                          content: TextField(
                            onChanged: (String value) {
                              tabName = value;
                            },
                          ),
                          actions: <Widget>[
                            ElevatedButton(
                              child: const Text("Add"),
                              onPressed: () {
                                setState(() {
                                  tabs.add(Tab(text: tabName));
                                  tabViewChildren.add(Container(height: 400));
                                });
                                Navigator.of(context).pop();
                              },
                            ),
                          ],
                        );
                      },
                    );
                  },
                  icon: const Icon(
                    Icons.add_box,
                  ),
                  label: const Text('Add Tab'),
                ),
                Opacity(
                  opacity: tabs.isNotEmpty ? 1 : 0.4,
                  child: ElevatedButton.icon(
                    onPressed: () {
                      showDialog(
                        context: context,
                        builder: (BuildContext context) {
                          return AlertDialog(
                            title: const Text("Select tab to remove"),
                            content: tabs.isNotEmpty
                                ? DropdownButton<String>(
                                    items: tabs
                                        .map((tab) => DropdownMenuItem<String>(
                                              value: tab.text,
                                              child: Text(tab.text ?? ""),
                                            ))
                                        .toList(),
                                    onChanged: (String? value) {
                                      setState(() {
                                        selectedTab = value;
                                      });
                                    },
                                    value: selectedTab,
                                  )
                                : Container(),
                            actions: <Widget>[
                              ElevatedButton(
                                child: const Text("Remove"),
                                onPressed: () {
                                  setState(() {
                                    int index = tabs.indexWhere((tab) => tab.text == selectedTab);
                                    tabs.removeAt(index);
                                    tabViewChildren.removeAt(index);
                                    selectedTab = tabs.isNotEmpty ? tabs[0].text : null;
                                  });
                                  Navigator.of(context).pop();
                                },
                              ),
                            ],
                          );
                        },
                      );
                    },
                    icon: const Icon(Icons.remove),
                    label: const Text('Remove Tab'),
                  ),
                ),
              ],
              title: const Text("Tab in Flutter"),
              bottom: TabBar(tabs: tabs),
            ),
            body: TabBarView(children: tabViewChildren)));
  }
}

Upvotes: 0

Views: 49

Answers (1)

Rami Al Debs
Rami Al Debs

Reputation: 121

The Problem: Flutter works as a tree, each node has its own build context so showDialog is returning a build with a new build context, therefore in your code whenever you call setState in the dialog => you are calling the setState for the parent context (page), basically, you are updating the Screen widget not the dialog widget.

The Solution: you have to use StatefulBuilder inside the Dialog widget so that it will have its own setState functionality. see the code below

import 'package:flutter/material.dart';

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

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

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Home(),
    );
  }
}

class Home extends StatefulWidget {
  const Home({super.key});

  @override
  HomeState createState() => HomeState();
}

class HomeState extends State<Home> {
  String? selectedTab = tabs[0].text;
  var tabName = "";

  static List<Tab> tabs = [
    const Tab(text: ""),
  ];

  List<Widget> tabViewChildren = [
    Container(
      height: 400,
    ),
  ];

  @override
  Widget build(BuildContext context) {
    return DefaultTabController(
        initialIndex: 0,
        length: tabs.length,
        child: Scaffold(
            appBar: AppBar(
              actions: <Widget>[
                ElevatedButton.icon(
                  onPressed: () {
                    showDialog(
                      context: context,
                      builder: (BuildContext context) {
                        return AlertDialog(
                          title: const Text("Enter tab name"),
                          content: TextField(
                            onChanged: (String value) {
                              tabName = value;
                            },
                          ),
                          actions: <Widget>[
                            ElevatedButton(
                              child: const Text("Add"),
                              onPressed: () {
                                setState(() {
                                  tabs.add(Tab(text: tabName));
                                  tabViewChildren.add(Container(height: 400));
                                });
                                Navigator.of(context).pop();
                              },
                            ),
                          ],
                        );
                      },
                    );
                  },
                  icon: const Icon(
                    Icons.add_box,
                  ),
                  label: const Text('Add Tab'),
                ),
                Opacity(
                  opacity: tabs.isNotEmpty ? 1 : 0.4,
                  child: ElevatedButton.icon(
                    onPressed: () {
                      showDialog(
                        context: context,
                        builder: (BuildContext context) {
                          return StatefulBuilder(
                            builder: (context, setState) => AlertDialog(
                              title: const Text("Select tab to remove"),
                              content: tabs.isNotEmpty
                                  ? DropdownButton<String>(
                                      items: tabs
                                          .map(
                                              (tab) => DropdownMenuItem<String>(
                                                    value: tab.text,
                                                    child: Text(tab.text ?? ""),
                                                  ))
                                          .toList(),
                                      onChanged: (String? value) {
                                        selectedTab = value;
                                        setState(() {});
                                      },
                                      value: selectedTab,
                                    )
                                  : Container(),
                              actions: <Widget>[
                                ElevatedButton(
                                  child: const Text("Remove"),
                                  onPressed: () {
                                    setState(() {
                                      int index = tabs.indexWhere(
                                          (tab) => tab.text == selectedTab);
                                      tabs.removeAt(index);
                                      tabViewChildren.removeAt(index);
                                      selectedTab =
                                          tabs.isNotEmpty ? tabs[0].text : null;
                                    });
                                    Navigator.of(context).pop();
                                  },
                                ),
                              ],
                            ),
                          );
                        },
                      );
                    },
                    icon: const Icon(Icons.remove),
                    label: const Text('Remove Tab'),
                  ),
                ),
              ],
              title: const Text("Tab in Flutter"),
              bottom: TabBar(tabs: tabs),
            ),
            body: TabBarView(children: tabViewChildren)));
  }
}

Upvotes: 2

Related Questions