Search code examples
flutteradaptive-layout

How can I use an appBar icon to open and close a ListView?


I am trying to create an app with a UI similar to Simplenote's. In the screenshot below, when the screenwidth > some value, the UI displays a ListView on the left and TextField on the right.:

screenshot

If the icon on the left side of the TextField's appBar is clicked, the ListView closes:

enter image description here

How do I code this? I'm not asking about an app Drawer, I think. I've already coded that app so that with narrow screenwidths users are presented with the ListView, click an item, and then the TextField's view is pushed. And with wider screenwidths users are presented with the ListView and TextField both visible. I'd like users to be able to click the appBar icon (in a wider view) and dismiss the ListView.


Solution

  • You can achieve this using callbacks, I prepared a sample for you.

    Result

    enter image description here

    Code:

    class NotesAppDemo extends StatefulWidget {
      const NotesAppDemo({super.key});
    
      @override
      State<NotesAppDemo> createState() => _NotesAppDemoState();
    }
    
    class _NotesAppDemoState extends State<NotesAppDemo> {
      bool showDetailsOnly = false;
    
      @override
      Widget build(BuildContext context) {
        return LayoutBuilder(builder: (context, constraints) {
          if (constraints.maxWidth > 300) {
            return Row(
              children: [
                if (!showDetailsOnly)
                  Expanded(
                    flex: 1,
                    child: MenuView(onMenuClicked: () {
                      setState(() {
                        showDetailsOnly = true;
                      });
                    }),
                  ),
                Expanded(
                  flex: 3,
                  child: DetailsView(
                    onMenuClicked: () {
                      setState(() {
                        showDetailsOnly = false;
                      });
                    },
                  ),
                ),
              ],
            );
          } else {
            return MenuView(
              onMenuClicked: () {
                //do any action for single view
              },
            );
          }
        });
      }
    }
    
    class MenuView extends StatelessWidget {
      const MenuView({
        required this.onMenuClicked,
        super.key,
      });
    
      final VoidCallback? onMenuClicked;
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            leading: IconButton(
              icon: const Icon(Icons.menu),
              onPressed: onMenuClicked,
            ),
            title: const Text('All Notes'),
          ),
          body: ListView(
            children: [
              ListTile(
                title: const Text('Notes'),
                onTap: () {
                  print('Notes');
                },
              ),
              ListTile(
                title: const Text('Details'),
                onTap: () {
                  print('Details');
                },
              ),
            ],
          ),
        );
      }
    }
    
    class DetailsView extends StatelessWidget {
      const DetailsView({
        required this.onMenuClicked,
        super.key,
      });
    
      final VoidCallback? onMenuClicked;
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            leading: IconButton(
              icon: const Icon(Icons.view_sidebar_sharp),
              onPressed: onMenuClicked,
            ),
          ),
          body: const Placeholder(),
        );
      }
    }