Content Description: Analyze the implementation of Flutter AppBar and complete GradientAppBar.

Recently, the project team decided to use Flutter to create a new App. During the development process, they encountered a need for a gradient AppBar.

That’s it, similar to AppBar in QQ:

With a UI library as powerful as Flutter, my first thought was that it could be supported, starting with the AppBar properties.


     

    AppBar({

    Key key,

    this.leading,

    this.automaticallyImplyLeading = true,

    this.title,

    this.actions,

    this.flexibleSpace,

    this.bottom,

    this.elevation,

    this.backgroundColor,

    this.brightness,

    this.iconTheme,

    this.textTheme,

    this.primary = true,

    this.centerTitle,

    this.titleSpacing = NavigationToolbar.kMiddleSpacing,

    This toolbarOpacity = 1.0,

    This bottomOpacity = 1.0,

    }) : assert(automaticallyImplyLeading ! = null),

    Assert (elevation = = null | | elevation > = 0.0).

    assert(primary ! = null),

    assert(titleSpacing ! = null),

    assert(toolbarOpacity ! = null),

    assert(bottomOpacity ! = null),

    PreferredSize = size.fromheight (kToolbarHeight + (bottom?.

    super(key: key);

Copy the code

I have a backgroundColor property,


     

    final Color backgroundColor;

Copy the code

Cool cool, Color type. Next, take a look at the online postings.

How to add gradient color in AppBar in flutter

https://stackoverflow.com/questions/50412484/how-to-add-gradient-color-in-appbar-in-flutter

The main idea is to inherit a PreferredSize class and implement the desired effect through Container + decoration. (In the Scaffold class the appBar parameter requires an object that implements the PreferredSizeWidget.)

The code from the article is posted here


     

    Widget build(BuildContext context) {

    return new Scaffold(

    appBar: new PreferredSize(

    child: new Container(

    padding: new EdgeInsets.only(

    top: MediaQuery.of(context).padding.top

    ),

    child: new Padding(

    padding: const EdgeInsets.only(

    Left: 30.0,

    Top: 20.0,

    Bottom: 20.0

    ),

    child: new Text(

    'Arnold Parge',

    style: new TextStyle(

    FontSize: 20.0.

    fontWeight: FontWeight.w500,

    color: Colors.white

    ),

    ),

    ),

    decoration: new BoxDecoration(

    gradient: new LinearGradient(

    colors: [

    Colors.red,

    Colors.yellow

    ]

    ),

    boxShadow: [

    new BoxShadow(

    color: Colors.grey[500],

    BlurRadius: 20.0.

    SpreadRadius: 1.0.

    )

    ]

    ),

    ),

    preferredSize: new Size(

    MediaQuery.of(context).size.width,

    150.0

    ),

    ),

    body: new Center(

    child: new Text('Hello'),

    ),

    );

    }

Copy the code

The effect of Flutter is not satisfactory. The leading and title of Flutter AppBar works well. Let’s do one ourselves!


     

    class AppBar extends StatefulWidget implements PreferredSizeWidget

Copy the code

Appbar inherits the StatefulWidget, so let’s just look at its State -> _AppBarState.

Go straight to the return of the Build method, back to front, to see how the AppBar is implemented.


     

    @override

    Widget build(BuildContext context) {

    // Omit some code, see later

    .

    final Brightness brightness = widget.brightness

    ?? appBarTheme.brightness

    ?? themeData.primaryColorBrightness;

    final SystemUiOverlayStyle overlayStyle = brightness == Brightness.dark

    ? SystemUiOverlayStyle.light

    : SystemUiOverlayStyle.dark;

    Return Semantics(// Access_semantics

    container: true,

    Child: AnnotatedRegion<SystemUiOverlayStyle>(// handles theme related, status bar text color

    value: overlayStyle,

    Child: Material(// Material control, handles colors, shadows and other effects

    color: widget.backgroundColor

    ?? appBarTheme.color

    ?? themeData.primaryColor,

    elevation: widget.elevation

    ?? appBarTheme.elevation

    ?? _defaultElevation,

    Child: Semantics(// Inside the child is the real content, we look inside the implementation of appBar.

    explicitChildNodes: true,

    child: appBar,

    ),

    ),

    ),

    );

    }

Copy the code

Returns a control that handles light and shade themes, colors, shadows, and child controls. We don’t want to use this color here.

Here the appBar is defined above:


     

    Widget appBar = ClipRect(// Clip its Widget with rectangle

    Child: CustomSingleChildLayout(// Constrain child Widgets by deleagate

    Delegate: const _ToolbarContainerLayout(), // Here the layout is a wide fill, and the height is kkToolbarHeight

    Child: IconTheme. Merge (// Process IconTheme

    Data: appBarIconTheme,// Handle the iconTheme value based on judgment

    Child: DefaultTextStyle(// Text style

    Style: sideStyle, // Handle the style value by judging the passed textTheme

    child: toolbar,

    ),

    ),

    ),

    );

Copy the code

As you can see here, this is the wrapper for a toolbar, and we move on to the Toolbar:


     

    // Here is a NavigationToolbar, and we set leading, title to use here

    final Widget toolbar = NavigationToolbar(

    leading: leading,

    middle: title,

    trailing: actions,

    centerMiddle: widget._getEffectiveCenterTitle(themeData),

    middleSpacing: widget.titleSpacing,

    );

Copy the code

There are also some processing inside appBar, such as processing bottom, adding SafeArea, etc., which will not be expanded here


     

    if (widget.bottom ! = null) { // bottom

    appBar = Column(

    mainAxisAlignment: MainAxisAlignment.spaceBetween,

    children: <Widget>[

    Flexible(

    child: ConstrainedBox(

    constraints: const BoxConstraints(maxHeight: kToolbarHeight),

    child: appBar,

    ),

    ),

    Widget. BottomOpacity = = 1.0? widget.bottom : Opacity(

    Opacity: const Interval(0.25, 1.0, curve: Curves. FastOutSlowIn). Transform (widget.bottomopacity),

    child: widget.bottom,

    ),

    ].

    );

    }

    // The padding applies to the toolbar and tabbar, not the flexible space.

    if (widget.primary) { // SafeArea

    appBar = SafeArea(

    top: true,

    child: appBar,

    );

    }

    appBar = Align( // Alignment.topCenter

    alignment: Alignment.topCenter,

    child: appBar,

    );

    if (widget.flexibleSpace ! = null) {// flexibleSpace effect

    appBar = Stack(

    fit: StackFit.passthrough,

    children: <Widget>[

    widget.flexibleSpace,

    appBar,

    ].

    );

    }

Copy the code

In AppBar, the colors are set in Material, and the most common Settings are set in toolbar, so the easiest way to color the Material’s Child layer is to leave the existing part unmodified.

The code is simple: copy the code for The AppBar, in this case called GradientAppBar, and modify it.

Add the initial and final values for the gradient color in the custom GradientAppBar constructor.


     

    GradientAppBar({

    .

    this.gradientStart,

    this.gradientEnd,

    }) : assert(automaticallyImplyLeading ! = null),

    .

    super(key: key);

    final Color gradientStart;

    final Color gradientEnd;

Copy the code

Let’s copy the code for the _AppBarState class, in this case _GradientAppBarState (remember to modify the createState method).

Then wrap the child in the build method return in the modification, using the passed color as the gradient background.


     

    Add the color gradient to the end of the build method, before return, using decoration

    if (widget.gradientStart ! = null && widget.gradientEnd ! = null) {

    appBar = Container(

    decoration: BoxDecoration(

    gradient: LinearGradient(

    colors: [widget.gradientStart, widget.gradientEnd]),

    ),

    child: appBar,

    );

    }

Copy the code

I’m going to do the Material color


     

    return Material(

    // Determine if gradient is used

    color: widget.gradientStart ! = null && widget.gradientEnd ! = null

    ? Colors.transparent

    : widget.backgroundColor ??

    appBarTheme.color ??

    themeData.primaryColor,

    elevation: widget.elevation ?? appBarTheme.elevation ?? _defaultElevation,

    Child: appBar, // Use the wrapped appBar

    );

Copy the code

This gives the gradient effect.

Using GradientAppBar replaces the original GradientAppBar with GradientAppBar.


     

    return Scaffold(

    appBar: PreferredSize(

    child: GradientAppBar(

    gradientStart: Color(0xFF49A2FC),

    gradientEnd: Color(0xFF2171F5),

    title: Text(widget.title),

    leading: Icon(Icons.ac_unit),

    ),

    preferredSize: Size.fromHeight(400),

    ),

    body: Center(

    child: Column(

    mainAxisAlignment: MainAxisAlignment.center,

    children: <Widget>[

    Text(

    'You have pushed the button this many times:',

    ),

    Text(

    '$_counter',

    style: Theme.of(context).textTheme.display1,

    ),

    ].

    ),

    ),

    floatingActionButton: FloatingActionButton(

    onPressed: _incrementCounter,

    tooltip: 'Increment',

    child: Icon(Icons.add),

    ), // This trailing comma makes auto-formatting nicer for build methods.

    );

Copy the code

Effect:

The project source code: https://github.com/loosaSH/flutter-appbar

This project will expand the SliverAppBar section later, give a star if you like

–END–

Identify the QR code, follow us