'How to update UI on the same page according to DropDownItem selected from Custom DropDown?

I have created a custom dropdown on a page which have a dropdown button, an overlay entry containing dropdown items. Now I want to change the other part of page excluding drop down button to change according to dropdown item clicked. e.g. If I click on Dashboard Item then overlay entry should be closed and Dashboard() widget should be displayed below dropdown button, if I click Orders, Orders() widget should be displayed.

Following is my code:

import 'package:flutter/material.dart';
import 'package:suture_house/User/UI/Screens/AccountOptions/account_details.dart';
import 'package:suture_house/User/UI/Screens/AccountOptions/addresses.dart';
import 'package:suture_house/User/UI/Screens/AccountOptions/dashboard.dart';
import 'package:suture_house/User/UI/Screens/AccountOptions/downloads.dart';

import 'AccountOptions/orders.dart';

class AccountPage extends StatefulWidget {
  final String text;

  const AccountPage({
    Key? key,
    required this.text,
  }) : super(key: key);

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

class _AccountPageState extends State<AccountPage> {
  GlobalKey? _actionKey;
  double height = 0.0, width = 0.0, xPosition = 0.0, yPosition = 0.0;
  bool isDropdownOpened = false;
  OverlayEntry? floatingDropDown;
  int _selectedIndex = 0;

  //List of pages to display as one of the children of ListView according to selected dropdown item
  final options = [
    Dashboard(),
    Orders(),
    Downloads(),
    Addresses(),
    AccountDetails()
  ];

  // void _onItemTapped(int index) {
  //   setState(() {
  //     _selectedIndex = index;
  //   });
  // }

  @override
  void initState() {
    // TODO: implement initState
    _actionKey = LabeledGlobalKey(widget.text);
    super.initState();
  }

  @override
  void dispose() {
    // TODO: implement dispose
    floatingDropDown!.remove();
    super.dispose();
  }

  //To get the position of Custom DropDown Button
  void findDropDownData() {
    RenderBox renderBox =
        _actionKey!.currentContext!.findRenderObject() as RenderBox;
    height = renderBox.size.height;
    width = renderBox.size.width;
    Offset offset = renderBox.localToGlobal(Offset.zero);
    xPosition = offset.dx;
    yPosition = offset.dy;
  }

  //Overlay Entry of DropDown Items
  OverlayEntry _createFloatingDropDown() {
    return OverlayEntry(builder: (context) {
      return Positioned(
        left: xPosition,
        width: width,
        top: yPosition + height,
        height: 6 * height + 60,

        child: DropDown(
          itemHeight: height,
        ),
      );
    });
  }

  @override
  Widget build(BuildContext context) {
    return ListView(
      children: [
        //Custom Drop down button
        Padding(
          padding: EdgeInsets.all(20),
          child: GestureDetector(
            key: _actionKey,
            onTap: () {
              setState(() {
                if (isDropdownOpened) {
                  floatingDropDown!.remove();
                } else {
                  findDropDownData();
                  floatingDropDown = _createFloatingDropDown();
                  Overlay.of(context)!.insert(floatingDropDown!);
                }

                isDropdownOpened = !isDropdownOpened;
              });
            },
            child: Container(
              decoration: BoxDecoration(
                  borderRadius: BorderRadius.circular(8), color: Colors.indigo),
              padding: EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
              child: Row(
                children: <Widget>[
                  Text(
                    widget.text,
                    style: TextStyle(color: Colors.white, fontSize: 20),
                  ),
                  Spacer(),
                  Icon(
                    Icons.arrow_drop_down,
                    color: Colors.white,
                  ),
                ],
              ),
            ),
          ),
        ),
        //Here I want to display different widgets according to DropDown Item clicked
        GestureDetector(
          onTap: () {
            if (isDropdownOpened) {
              floatingDropDown!.remove();
              isDropdownOpened = false;
            }
          },
          child: Container(
            height: 1000,

          )
        )
      ],
    );
  }
}


//This DropDown will be displayed on Overlay Entry
class DropDown extends StatelessWidget {
  final double itemHeight;
  //final void Function(int) onOptionTap;

  const DropDown({Key? key, required this.itemHeight,}) : super(key: key);


  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        SizedBox(
          height: 5,
        ),
        Align(
          alignment: Alignment(-0.85, 0),
          child: ClipPath(
            clipper: ArrowClipper(),
            child: Container(
              height: 20,
              width: 30,
              decoration: BoxDecoration(
                color: Colors.indigo,
              ),
            ),
          ),
        ),
        Material(
          elevation: 20,
          shape: ArrowShape(),
          child: Container(
            height: 6 * itemHeight,
            decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(8),
            ),
            child: Column(
              children: [
                DropDownItem.first(
                    text: 'Dashboard',
                    iconData: Icons.speed_outlined,
                    index: 0,
                    isSelected: true),
                DropDownItem(
                    text: 'Orders',
                    iconData: Icons.shopping_bag_outlined,
                    index: 1,
                    isSelected: false),
                DropDownItem(
                    text: 'Downloads',
                    iconData: Icons.insert_drive_file_outlined,
                    index: 2,
                    isSelected: false),
                DropDownItem(
                    text: 'Addresses',
                    iconData: Icons.edit_location,
                    index: 3,
                    isSelected: false),
                DropDownItem(
                    text: 'Account Details',
                    iconData: Icons.person_outline,
                    index: 4,
                    isSelected: false),
                DropDownItem.last(
                    text: 'Logout',
                    iconData: Icons.exit_to_app_outlined,
                    index: 5,
                    isSelected: false),
              ],
            ),
          ),
        )
      ],
    );
  }

}

//DropDown Items
class DropDownItem extends StatelessWidget {
  final String text;
  final IconData iconData;
  bool isSelected;
  final bool isFirstItem;
  final bool isLastItem;
  final int index;

  DropDownItem({
    Key? key,
    required this.text,
    required this.iconData,
    required this.isSelected,
    this.isFirstItem = false,
    this.isLastItem = false,
    required this.index,
  }) : super(key: key);

  factory DropDownItem.first(
      {required String text,
      required IconData iconData,
      required bool isSelected,
      required int index}) {
    return DropDownItem(
      text: text,
      iconData: iconData,
      isFirstItem: true,
      isSelected: isSelected,
      index: index,
    );
  }

  factory DropDownItem.last(
      {required String text,
      required IconData iconData,
      required bool isSelected,
      required int index}) {
    return DropDownItem(
      text: text,
      iconData: iconData,
      isLastItem: true,
      isSelected: isSelected,
      index: index,
    );
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      child: Container(
        decoration: BoxDecoration(
            borderRadius: BorderRadius.vertical(
                top: isFirstItem ? Radius.circular(8) : Radius.zero,
                bottom: isLastItem ? Radius.circular(8) : Radius.zero),
            color: isSelected ? Colors.orangeAccent : Colors.indigo),
        padding: EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
        child: Row(
          children: <Widget>[
            Text(
              text,
              style: TextStyle(color: Colors.white, fontSize: 20),
            ),
            Spacer(),
            Icon(
              iconData,
              color: Colors.white,
            ),
          ],
        ),
      ),
    );
  }
}

class ArrowClipper extends CustomClipper<Path> {
  @override
  Path getClip(Size size) {
    Path path = Path();

    path.moveTo(0, size.height);
    path.lineTo(size.width / 2, 0);
    path.lineTo(size.width, size.height);

    return path;
  }

  @override
  bool shouldReclip(covariant CustomClipper<Path> oldClipper) => true;
}

class ArrowShape extends ShapeBorder {
  @override
  // TODO: implement dimensions
  EdgeInsetsGeometry get dimensions => throw UnimplementedError();

  @override
  Path getInnerPath(Rect rect, {TextDirection? textDirection}) {
    // TODO: implement getInnerPath
    throw UnimplementedError();
  }

  @override
  Path getOuterPath(Rect rect, {TextDirection? textDirection}) {
    // TODO: implement getOuterPath
    return getClip(rect.size);
    //throw UnimplementedError();
  }

  @override
  void paint(Canvas canvas, Rect rect, {TextDirection? textDirection}) {
    // TODO: implement paint
  }

  @override
  ShapeBorder scale(double t) {
    // TODO: implement scale
    throw UnimplementedError();
  }

  Path getClip(Size size) {
    Path path = Path();

    path.moveTo(0, size.height);
    path.lineTo(size.width / 2, 0);
    path.lineTo(size.width, size.height);

    return path;
  }
}

This is the UI of application. I want to change the UI below "View Options" according to item selected.

enter image description here



Solution 1:[1]

use option[_selectedIndex] wherever you want to show the widget.

Solution 2:[2]

You can use conditions to update your UI based on the option chosen, so when you make the change you're doing using options[_selectedIndex] then you have the option that you want to display and then you can do something like this

options[_selectedIndex]==dashboard? dashboardWidget(): 
options[_selectedIndex]==settings? settingsWidget():defaultWidget(),

and I recommend You using Enums that'll help reduce your code and make it more flexible for upcoming changes or maintainance of the code

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Lakshydeep Vikram Sah
Solution 2 Mohamed El-Marakby