SliverAppBar in Flutter

 


    Flutter uses the well-known AppBar to create a toolbar, but when we need a dynamic toolbar that will show content on swipe, we use the excellent SliverAppBar widget.

    Both Both widgets allow you to make your application a little prettier, which is no doubt very simple in Flutter. 

    I have seen many questions on StackOverflow and Facebook groups about how the AppBar and SliverAppBar can be changed in terms of behavior or design.

    Let's look at two tasks.

    Task 1

    We want to create a non-screwed AppBar, but not in the usual way. We want to add a Drawer that the AppBar will respond to when opened. That's it: our own AppBar with the dimensions we need.


    The problem is that, as we know, the AppBar has a default size, and we cannot change it. Looking at the source code, we see the AppBar parameter in Scaffold, we see that it accepts a PreferredSizeWidget widget, now we look at the source code of the AppBar and find out that this is only a StatefulWidget that implements PreferredSizeWidget.

    This is what we want


    How would I do this so that when the menu button of our AppBar is pressed, the side menu opens.


    We can do this in two ways:


    Using `AppBar`

class Sample1 extends StatelessWidget { @override Widget build(BuildContext context) { return SafeArea( child: Scaffold( drawer: Drawer(), appBar: MyCustomAppBar( height: 150, ), body: Center( child: FlutterLogo( size: MediaQuery.of(context).size.width / 2, ), ), ), ); } } class MyCustomAppBar extends StatelessWidget implements PreferredSizeWidget { final double height; const MyCustomAppBar({ Key key, @required this.height, }) : super(key: key); @override Widget build(BuildContext context) { return Column( children: [ Container( color: Colors.grey[300], child: Padding( padding: EdgeInsets.all(30), child: AppBar( title: Container( color: Colors.white, child: TextField( decoration: InputDecoration( hintText: "Search", contentPadding: EdgeInsets.all(10), ), ), ), actions: [ IconButton( icon: Icon(Icons.verified_user), onPressed: () => null, ), ], ) , ), ), ], ); } @override Size get preferredSize => Size.fromHeight(height); }

    
    Using a custom widget

    Here we have more flexibility and we can use the GlobalKey of type ScaffoldState or InheritedWidget from Scaffold, thus gaining access to the state methods to open the Drawer.
    
import 'package:flutter/material.dart'; class Sample1 extends StatelessWidget { @override Widget build(BuildContext context) { return SafeArea( child: Scaffold( drawer: Drawer(), appBar: MyCustomAppBar( height: 150, ), body: Center( child: FlutterLogo( size: MediaQuery.of(context).size.width / 2, ), ), ), ); } } class MyCustomAppBar extends StatelessWidget implements PreferredSizeWidget { final double height; const MyCustomAppBar({ Key key, @required this.height, }) : super(key: key); @override Widget build(BuildContext context) { return Column( children: [ Container( color: Colors.grey[300], child: Padding( padding: EdgeInsets.all(30), child: Container( color: Colors.red, padding: EdgeInsets.all(5), child: Row(children: [ IconButton( icon: Icon(Icons.menu), onPressed: () { Scaffold.of(context).openDrawer(); }, ), Expanded( child: Container( color: Colors.white, child: TextField( decoration: InputDecoration( hintText: "Search", contentPadding: EdgeInsets.all(10), ), ), ), ), IconButton( icon: Icon(Icons.verified_user), onPressed: () => null, ), ]), ), ), ), ], ); } @override Size get preferredSize => Size.fromHeight(height); }
    
    Result


    Task 2


    As we know, SliverAppBar works like this:


    What we want is to put the Card embedded in our SliverAppBar, as shown in the following image.


    Wait, but the content inside the SliverAppBar is being clipped, so it can't go out of bounds, what should I do?


    Don't panic, let's take a look at the source code for SliverAppBar and, surprise, this is a StatefulWidget using SliverPersistentHeader internally, that's the secret.


    We will create our own SliverPersistentHeaderDelegate to use the SliverPersistentHeader.

class Sample2 extends StatelessWidget { @override Widget build(BuildContext context) { return SafeArea( child: Material( child: CustomScrollView( slivers: [ SliverPersistentHeader( delegate: MySliverAppBar(expandedHeight: 200), pinned: true, ), SliverList( delegate: SliverChildBuilderDelegate( (_, index) => ListTile( title: Text("Index: $index"), ), ), ) ], ), ), ); } } class MySliverAppBar extends SliverPersistentHeaderDelegate { final double expandedHeight; MySliverAppBar({@required this.expandedHeight}); @override Widget build( BuildContext context, double shrinkOffset, bool overlapsContent) { return Stack( fit: StackFit.expand, overflow: Overflow.visible, children: [ Image.network( "https://images.pexels.com/photos/396547/pexels-photo-396547.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500", fit: BoxFit.cover, ), Center( child: Opacity( opacity: shrinkOffset / expandedHeight, child: Text( "MySliverAppBar", style: TextStyle( color: Colors.white, fontWeight: FontWeight.w700, fontSize: 23, ), ), ), ), Positioned( top: expandedHeight / 2 - shrinkOffset, left: MediaQuery.of(context).size.width / 4, child: Opacity( opacity: (1 - shrinkOffset / expandedHeight), child: Card( elevation: 10, child: SizedBox( height: expandedHeight, width: MediaQuery.of(context).size.width / 2, child: FlutterLogo(), ), ), ), ), ], ); } @override double get maxExtent => expandedHeight; @override double get minExtent => kToolbarHeight; @override bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) => true; }

Result



Done, both tasks solved.




Conclusion:

 In the article, I have explained SliverAppBar basic structure in a flutter; Often we despair when we do not find any properties in a widget, but we just need to look at its source code to understand how it is implemented in Flutter, thus discovering options for implementing our own widgets.

❤ ❤ Thanks for reading this article ❤❤

Комментарии

Популярные сообщения из этого блога

Shimmer effect by Flutter

Carousel Slider in Flutter

Diagram in Flutter