flutterparallaxmaterial3sliverappbar

Flutter: How to Material 3 theme FlexibleSpaceBar so it fades to the scrolled down AppBar color?


I have a hero image, consisting of a SliverAppBar with a child of FlexibleSpaceBar containing the hero image.

When the user scrolls down the page the hero image scrolls up fading to white. White is the initial colour of the appbar.

But, as per material3, as the user scrolls the appbar transitions from its initial color to be a brighter, saturated version of the page's background colour.

So for some time I have an envelope of white, which was the hero image, meeting the brightly saturated appbar. This looks shabby.

enter image description here

You can see beneath the Appbar title "Samuel" there is a window of white. This is the hero image having faded out.

How do I modify this to be material 3? I think really that window of white should match the Appbar's colour. How do I do that?

    return NestedScrollView(
    headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
      return <Widget>[
        SliverAppBar(
          expandedHeight: (widget.neighbour.picUrl ?? "") != ""
              ? (MediaQuery.of(context).size.width * 4/3) : 256, //300,
          automaticallyImplyLeading: false, // removes back arrow over pic.
          flexibleSpace: FlexibleSpaceBar(
            background: profilePicWidget,
            title: Text(widget.neighbour.firstName ??
                widget.neighbour.surname ??
                ""),
          ),
        ),
      ];
    },
    body: Theme(
      data: Theme.of(context),
      child: ListView(children: [

This is the hero image, AKA profilePicWidget

        profilePicWidget = FittedBox(
        fit: BoxFit.fitWidth,
        child: Align(
            heightFactor: 1,//0.7,
            alignment: Alignment.topCenter,
            child: Center(
                child: Hero(
                    tag:
                        "Loaner${widget.neighbour.firebaseId}",
                    child: Material(
                      child: InkWell(
                        onTap: () => Navigator.pop(context),
                        child: (widget.neighbour.picUrl != null)
                            ? CachedNetworkImage(
                          progressIndicatorBuilder: (context, url, downloadProgress) =>
                              Container(child:
                              CircularProgressIndicator(value: downloadProgress.progress,
                                valueColor:
                                AlwaysStoppedAnimation<Color>(themeColor),),
                                  width: 50.0,
                                  height: 50.0,
                                  padding: EdgeInsets.all(15.0),
                                ),
                                imageUrl: widget.neighbour.picUrl!,
                                fit: BoxFit.cover,
                                errorWidget: (context, url, error) //=>
                                {
                                  print(LOG + "Failed to load picUrl, error: $error");
                                    return Padding(
                                    padding: EdgeInsets.fromLTRB(0, 0, 0, 48),
                                    child: Image.asset(
                                      PersonUtils.getAvatarFromId[//if avatar is Ninja, go highRes ninja
                                          widget.neighbour.avatar == 99 ? 100 : widget.neighbour.avatar]!,
                                      width: 256,
                                    ));
                                }
                              )
                            : Padding(
                                padding: EdgeInsets.fromLTRB(0, 0, 0, 16),
                                child: Image.asset(
                                  PersonUtils.getAvatarFromId[
                                    widget.neighbour.avatar == 99 ? 100 : widget.neighbour.avatar]!,
                                  width: 256,
                                )),
                      ),
                    )))));

Solution

  • Add the AppBarSystemChromeController inside your build method before returning the Scaffold. This will adjust the system UI colors according to the AppBar's color. Also, consider wrapping your FittedBox in a Container to control the background color.

    AppBarSystemChromeController(
      // AppBar's color
      brightness: Brightness.light,
      backgroundColor: appBarBackgroundColor, // set AppBar's background
      // Other AppBar styling properties
    
    
      statusBarBrightness: Brightness.dark,
      statusBarColor: appBarBackgroundColor, //AppBar's background color 
      systemNavigationBarColor: appBarBackgroundColor, //  AppBar's background 
      systemNavigationBarIconBrightness: Brightness.dark,
      child: Scaffold(
        body: NestedScrollView(
          headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
            return <Widget>[
              SliverAppBar(
                // other properties
              ),
            ];
          },
          body: Theme(
            // theme 
            child: ListView(
              children: [
                // ListView children
                Container(
                  color: appBarBackgroundColor, // set the same color as your AppBar
                  child: profilePicWidget, // Your hero image widget
                ),
                // other widgets
              ],
            ),
          ),
        ),
      ),
    ),