Skip to content

AppBar action needs a key to see its own Scaffold  #4581

Closed

Description

@HansMuller

[This is an instance of a general issue and it could equally well be titled: 'Patterns for referring (using .of) to widgets introduced in the same build function']

Apps commonly have a single widget that contains a Scaffold and an AppBar. It's inconvenient that the AppBar's actions can't refer to the Scaffold directly. This can be overcome by providing the Scaffold with a key as in the example below.

It would be convenient if Scaffold.of(context) would return the Scaffold contained by context if there was no Scaffold ancestor.

Creating a GlobalKey to refer to the Scaffold can be fraught, see #4579.

import 'package:flutter/material.dart';

class Home extends StatelessWidget {

  // The AppBar's action needs this key to find its own Scaffold.
  final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      key: _scaffoldKey,
      appBar: new AppBar(
        title: new Text('Home'),
        actions: <Widget>[
          new IconButton(
            icon: Icons.shopping_cart,
            onPressed: () {
              // Scaffold.of(context) == null because our context contains
              // Scaffold. So we have to give the Scaffold a GlobalKey
              // and use it here.
              _scaffoldKey.currentState.showSnackBar(new SnackBar(
                content: new Text('$_scaffoldKey')
              ));
            }
          )
        ]
      ),
      body: new Center(child: new Text('Click the shopping cart'))
    );
  }
}

void main() {
  runApp(new MaterialApp(home: new Home()));
}

Activity

  1. modified the milestone: on Aug 1, 2016
  2. added
    frameworkflutter/packages/flutter repository. See also f: labels.
    on Sep 12, 2016
  3. vy0592 commented on Oct 14, 2016

    @vy0592

    I'm running into the same issue. The workaround works but I'd still prefer snackbar can find its own scaffold without a global key.

  4. Hixie commented on Oct 14, 2016

    @Hixie
    Contributor

    One workaround is to put a Builder widget in the tree and use its context instead.

  5. Hixie commented on Oct 14, 2016

    @Hixie
    Contributor

    something like:

      @override
      Widget build(BuildContext context) {
        return new Scaffold(
          key: _scaffoldKey,
          appBar: new Builder(
            builder: (BuildContext context) { // <-- new widget inserted here
              return new AppBar(
                title: new Text('Home'),
                actions: <Widget>[
                  new IconButton(
                    icon: Icons.shopping_cart,
                    onPressed: () {
                      // here "context" is from the Builder closure, so it's under the Scaffold
                      Scaffold.of(context).showSnackBar(new SnackBar(
                        content: new Text('$_scaffoldKey')
                      ));
                    }
                  )
                ]
              );
            },
          ),
          body: new Center(child: new Text('Click the shopping cart'))
        );
      }
  6. changed the title [-]AppBar action needs a key to see its own Scaffold[/-] [+]Patterns for referring (using .of) to widgets introduced in the same build function[/+] on Dec 29, 2016
  7. Hixie commented on Dec 29, 2016

    @Hixie
    Contributor

    This is a general issue, not really specific to AppBar. GlobalKey and Builder are the current state of the art solutions. If GlobalKey and Builder are not sufficient, please reopen this bug with more information explaining why.

  8. HansMuller commented on Jan 6, 2017

    @HansMuller
    ContributorAuthor

    This is in fact an AppBar issue because the type of Scaffold's AppBar is AppBar, not Widget. The suggested workaround doesn't compile.

    Hopefully the "great Scrollable refactor" will eliminate this issue.

  9. changed the title [-]Patterns for referring (using .of) to widgets introduced in the same build function[/-] [+] AppBar action needs a key to see its own Scaffold [/+] on Jan 6, 2017
  10. modified the milestones: 2: Make Early Adopters happy, on Jan 11, 2017
  11. abarth commented on Feb 10, 2017

    @abarth
    Contributor

    Still a problem but likely a trivial fix now.

  12. changed the title [-] AppBar action needs a key to see its own Scaffold [/-] [+]Scaffold.appBar doesn't accept widgets that aren't AppBars.[/+] on Feb 17, 2017
  13. changed the title [-]Scaffold.appBar doesn't accept widgets that aren't AppBars.[/-] [+]AppBar action needs a key to see its own Scaffold [/+] on Apr 12, 2017
  14. HansMuller commented on Apr 12, 2017

    @HansMuller
    ContributorAuthor

    I'm closing the original issue, since we're not planning to do anything about it.

    I've opened a new issue, #9349, which covers the problem this issue had morphed into (the type of Scaffold's appBar property is AppBar not Widget).

  15. fabiomotiws commented on Sep 13, 2018

    @fabiomotiws

    Hi, I dit it, work for me :)

    @override
    Widget build(BuildContext context) {
      return new Scaffold(
        appBar: new AppBar(
          title: new Text('Demo')
        ),
        body: new Builder(
          // Create an inner BuildContext so that the onPressed methods
          // can refer to the Scaffold with Scaffold.of().
          builder: (BuildContext context) {
            return new Center(
              child: new RaisedButton(
                child: new Text('SHOW A SNACKBAR'),
                onPressed: () {
                  Scaffold.of(context).showSnackBar(new SnackBar(
                    content: new Text('Hello!'),
                  ));
                },
              ),
            );
          },
        ),
      );
    }
  16. kszyrvercobrador commented on Sep 18, 2018

    @kszyrvercobrador

    @Hixie Putting builder on appBar triggers this error.

    image

  17. Hixie commented on Oct 2, 2018

    @Hixie
    Contributor

    Can you post your actual code? (Maybe file a new bug.)

    In general appBar needs the widget to implement PreferredSizeWidget (e.g. it could be a PreferredSize widget or an AppBar), but exactly what you do to work around that depends on what you're trying to do.

  18. eddiegroves commented on Dec 10, 2018

    @eddiegroves

    Here's how I solved showing a ShackBar via AppBar, hopefully this is the correct use of PreferredSizeWidget.

    appBar: PreferredSize(
      preferredSize: Size.fromHeight(kToolbarHeight),
      child: Builder(
        builder: (context) => AppBar(...),
      ),
    ),
    
  19. gazialankus commented on Dec 31, 2018

    @gazialankus
    Contributor

    Another alternative is to wrap things inside AppBar with a Builder each. This works for me:

        return Scaffold(
          appBar: AppBar(
            title: Text(widget.title),
            actions: <Widget>[
              Builder(builder: (context) {
                return IconButton(
                  icon: Icon(Icons.edit),
                  onPressed: () {
                    try{
                      print(Scaffold.of(context));
                    } catch (e) {
                      print(e);
                    }
                  },
                );
              }),
            ],
          ),
    
    
  20. github-actions commented on Aug 31, 2021

    @github-actions

    This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

  21. locked as resolved and limited conversation to collaborators on Aug 31, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    c: API breakBackwards-incompatible API changesframeworkflutter/packages/flutter repository. See also f: labels.

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions