Drawer only opens when Scaffold Key is updated

Viewed 65

So I have a Scaffold Key in my Scaffold:

  final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();

And in my Scaffold I have a custom Drawer and a custom App Bar:

Scaffold(
    key: _scaffoldKey,
    backgroundColor: Color(0xFF3FC1C9),
    drawer: HomeDrawer(),
    body: StartAppBar(_scaffoldKey.currentState?.openDrawer),
  ),

Im passing the open Drawer function on to the custom AppBar. My custom AppBar accepts the function like this:

class StartAppBar extends StatelessWidget {
  void Function()? openDrawer;
  StartAppBar(this.openDrawer);

and references it here:

    leading: IconButton(
      onPressed: () {
        openDrawer!();
        // _key.currentState!.openEndDrawer();
      },
      icon: Icon(
        Icons.view_headline_rounded,
      ),
    ),

The problem is that from default the function triggers a null pointer

Null check operator used on a null value

Full Code

My class where I create the key looks like this:

class HomeScreen extends StatefulWidget {
  final marken;
  const HomeScreen({Key? key, this.marken}) : super(key: key);
  @override
  _HomeScreenState createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  late List<Widget> _widgetOptions;

  @override
  initState() {
    _widgetOptions = <Widget>[
      Favorites(),
      BodyHomeScreen(
        marken: widget.marken,
      ),
      Kontakt(),
    ];
  }

  DateTime? lastPressed;
  final HideNavbar hiding = HideNavbar();
  int _selectedIndex = 1;

  void _onItemTap(int index) {
    setState(() {
      _selectedIndex = index;
    });
  }

  final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () => FocusManager.instance.primaryFocus?.unfocus(),
      child: Scaffold(
        key: _scaffoldKey,
        backgroundColor: Color(0xFF3FC1C9),
        drawer: HomeDrawer(),
        body: StartAppBar(_selectedIndex, hiding, lastPressed, _widgetOptions,
            _scaffoldKey.currentState?.openDrawer),
        bottomNavigationBar: BottomBar(
          _onItemTap,
          _selectedIndex,
          hiding,
        ),
      ),
    );
  }
}

As also seen above im passing the key on to the StartAppBar, that looks like this:

import 'package:flutter/material.dart';

class StartAppBar extends StatelessWidget {
  final int selectedIndex;
  final hiding;
  List<Widget> widgetOptions;
  var lastPressed;
  void Function()? openDrawer;
  StartAppBar(this.selectedIndex, this.hiding, this.lastPressed,
      this.widgetOptions, this.openDrawer);

  @override
  Widget build(BuildContext context) {
    return WillPopScope(
      onWillPop: () async {
        final now = DateTime.now();
        final maxDuration = Duration(seconds: 2);
        final isWarning =
            lastPressed == null || now.difference(lastPressed!) > maxDuration;

        if (isWarning) {
          lastPressed = DateTime.now();

          final snackBar = SnackBar(
            content: Container(
              //color: Colors.white,
              decoration: BoxDecoration(
                  color: Color(0xFF03DAC6),
                  borderRadius: BorderRadius.circular(20)),
              margin: EdgeInsets.fromLTRB(0, 0, 0, 20),
              child: Padding(
                padding: const EdgeInsets.all(8.0),
                child: Text(
                  'Doppelklick zum verlassen',
                  textAlign: TextAlign.center,
                ),
              ),
            ),
            backgroundColor: Colors.transparent,
            elevation: 1000,
            behavior: SnackBarBehavior.floating,
            duration: maxDuration,
          );

          ScaffoldMessenger.of(context)
            ..removeCurrentSnackBar()
            ..showSnackBar(snackBar);

          return false;
        } else {
          return true;
        }
      },
      child: CustomScrollView(
        controller: hiding.controller,
        slivers: [
          SliverAppBar(
            backgroundColor: Color(0xFF3FC1C9),
            automaticallyImplyLeading: false,
            elevation: 0,
            title: Text(
              "AutoLab",
              style:
                  TextStyle(color: Colors.white, fontWeight: FontWeight.bold),
            ),
            leading: IconButton(
              onPressed: () {
                openDrawer?.call();
                // _key.currentState!.openEndDrawer();
              },
              icon: Icon(
                Icons.view_headline_rounded,
              ),
            ),
            centerTitle: true,
            expandedHeight: 120,
            floating: false,
            flexibleSpace: FlexibleSpaceBar(
              title: selectedIndex == 1
                  ? Text("Marke auswählen")
                  : selectedIndex == 2
                      ? Text("Schreibe uns!")
                      : Text("Deine Modelle"),
              centerTitle: true,
            ),
          ),
          SliverToBoxAdapter(child: widgetOptions.elementAt(selectedIndex)),
        ],
      ),
    );
  }
}

Any ideas how I can fix this behaviour?

1 Answers

Problem:

The error is because the openDrawer variable is null and you're using a null-check (!) on a null variable.

Solution:

Change this:

openDrawer!();

to this:

openDrawer?.call();

This ensures the openDrawer method only runs when it is not null.

Checkout Understanding null safety | Dart for more information about Dart's null safety.

Related