Create interesting scrolling effects in Flutter – Sliver series

Time:2019-10-9

Create interesting scrolling effects in Flutter - Sliver series

1. Preface

FlutterAs one of the most popular technologies nowadays, it has already attracted the attention of a large number of technology enthusiasts, even some of them, by virtue of its excellent performance and the advantage of smoothing out the differences among many terminals.Idle fishAmerican LeaguetencentLarge companies have been put into operation. Although its ecology is not yet fully mature, it lies behind it.GoogleBlessing, the speed of its development is astonishing enough to foresee the future.FlutterThe demand for developers will grow as well.

Whether it’s for technology sake or for possible future job opportunities, 9102, as a front-end developer, there seems to be no reason not to try it. It is with this mentality that the author began to learn.FlutterAt the same time, a warehouse for practice has been built, and all subsequent codes will be hosted on it. Welcome to Star and learn together. This is my flutter series:

  • Using Flutter to Build a Beautiful UI Interface-Basic Component Chapter
  • Flutter Rolling Container Components – ListView
  • Flutter Grid Layout – GridView
  • Using custom Icon in Flutter

In previous articles, we learned how to use it.ListViewandGridViewThese two scroll type components. Today, let’s learn about another rolling componentCustomScrollViewAnd its collocationSliverSeries components. With them in hand, you can do some interesting rolling effects.~

2. Essential knowledge

Before we get into today’s topic, let’s take a brief look at today’s two protagonists.CustomScrollViewandSliverCustomScrollViewyesFlutterProvides components that can be used to customize rolling effects, which can be as glued as multipleSliverStick together.

What does that mean? Take a chestnut (you can also click here to see it)youtubeOn a video:

If there is one in the page at the same timeListAnd oneGridAlthough they seem to be a whole, there is no guarantee of a consistent rolling effect due to the separation of their rolling effects.

And useCustomScrollViewComponents act as rolling containers.SliverListandSliverGridSeparate substitutionListandGridAsCustomScrollViewSubcomponents, scrolling effects are then determined byCustomScrollViewUnified control, that’s all.

amongSliverListandSliverGridThat’s what we mentioned earlier.SliverTwo members of the series, besides,SliverThere are also several common family members:

  • SliverAppBar:Creates a material design app bar that can be placed in a CustomScrollView.
  • SliverPersistentHeader:Creates a sliver that varies its size when it is scrolled to the start of a viewport.
  • SliverFillRemaining:Creates a sliver that fills the remaining space in the viewport.
  • SliverToBoxAdapter:Creates a sliver that contains a single box widget.
  • SliverPadding:Creates a sliver that applies padding on each side of another sliver.

Note: BecauseCustomeScrollViewSubcomponents can only beSliverSeries, so if you want to cram a common component into itCustomScrollViewBe sure to use this componentSliverToBoxAdapterPacking.

3. Warm-up: SliverList / SliverGrid

So many of the concepts mentioned above seem a bit boring, so let’s start with the simplest example and see how to use them.CustomScrollViewandSliverList/SliverGrid

actuallyCustomScrollViewThe usage is simple. It has one.sliversAttribute, is aWidgetArray, just put all the subcomponents in it. Some other rolling-related properties are basically what we learned before.ListViewAlmost.

CustomScrollView(
  slivers: <Widget>[
    renderSliverA(),
    renderSliverB(),
    renderSliverC(),
  ],
)

Let’s have a look again.SliverListIt has only onedelegateAttributes can be usedSliverChildListDelegateorSliverChildBuilderDelegateThese two classes are implemented. The former will render all the sub-components at one time, and the latter will render the current elements according to the window. The effect of the former can be compared with that of the latter.ListViewandListView.buildThe two constructors are analogous.

SliverList(
  delegate: SliverChildListDelegate(
    <Widget>[
      renderA(),
      renderB(),
      renderC(),
    ]
  )
)

SliverList(
  delegate: SliverChildBuilderDelegate(
    (context, index) => renderItem(context, index),
    childCount: 10,
  )
)

From the example above, we find thatSliverListWays of use andListViewIt’s much the same, but it’s not the same.SliverGridThe same is true. Let’s not go into too much detail here. Let’s look at an example of two columns of grids:

SliverGrid.count(
  crossAxisCount: 2,
  children: <Widget>[
    renderA(),
    renderB(),
    renderC(),
    renderD()
  ]
)

Next, let’s combine the above three points through a practical example.

Code (see here for the full version)

final List<Color> colorList = [
  Colors.red,
  Colors.orange,
  Colors.green,
  Colors.purple,
  Colors.blue,
  Colors.yellow,
  Colors.pink,
  Colors.teal,
  Colors.deepPurpleAccent
];

// The Text component needs to be wrapped in SliverToBox Adapter to be a subcomponent of CustomScrollView
Widget renderTitle(String title) {
  return SliverToBoxAdapter(
    child: Padding(
      padding: EdgeInsets.symmetric(vertical: 16),
      child: Text(
        title,
        textAlign: TextAlign.center,
        style: TextStyle(fontSize: 20),
      ),
    ),
  );
}

CustomScrollView(
  slivers: <Widget>[
    renderTitle('SliverGrid'),
    SliverGrid.count(
      crossAxisCount: 3,
      children: colorList.map((color) => Container(color: color)).toList(),
    ),
    renderTitle('SliverList'),
    SliverFixed ExtentList (// SliverList's grammatical sugar, used for Lists of fixed height per item
      delegate: SliverChildBuilderDelegate(
        (context, index) => Container(color: colorList[index]),
        childCount: colorList.length,
      ),
      itemExtent: 100,
    ),
  ],
)

Design sketch

Create interesting scrolling effects in Flutter - Sliver series

Another thing to note in the above example is that we put the title component in theSliverToBoxAdapterNext, becauseCustomScrollViewadmit of only interpretationSliverSeries of components.

4. Liver AppBar

AppBarIs often used to build a page headerBarThe components of theCustomScrollViewIt corresponds toSliverAppBarComponents. What’s the magic of it? As the page scrolls, the headerBarThere will be an effect of closing the transition. Let’s first look at the effect:

Float effect Snap effect Pinned effect
Create interesting scrolling effects in Flutter - Sliver series Create interesting scrolling effects in Flutter - Sliver series Create interesting scrolling effects in Flutter - Sliver series

From the preview above, you must be curious.SliverAppBarHow to achieve the transitional effect in ~Don’t worry, let’s first see how to use it:

SliverAppBar(
  floating: true,
  snap: true,
  pinned: true,
  expandedHeight: 250,
  flexibleSpace: FlexibleSpaceBar(
    title: Text(this.title),
    background: Image.network(
      'http://img1.mukewang.com/5c18cf540001ac8206000338.jpg',
      fit: BoxFit.cover,
    ),
  ),
)

SliverAppBarThe most important attributes are listed in the examples above. Among them:

  • expandedHeightIn the unfolding stateappBarHeight, that is, the space occupied by the picture in the picture;
  • flexibleSpaceComponents with variable size of space,FlutterGive us a ready-made one.FlexibleSpaceBarComponents. Handle them for us.titleThe effect of transition.

In addition,floating/snap/pinnedThese three attributes can be specifiedSliverAppBarThe presentation of content after it slides out of the screen.

  • floatWhen sliding down, even at presentCustomScrollViewNot at the top.SliverAppBarThey will also appear downward together.
  • snapWhen the finger is released,SliverAppBarIt will be adjusted according to its current position and will remain unchanged.OpenorPut it awayThe state of being;
  • pinnedDifferent from:floatEffectiveness, whenSliverAppBarWhen the content slides out of the screen, it will always render a closed state component fixed at the top.

It should be noted that:snapThe effect must be infloatbytrueOnly then will it take effect. In addition, you can use the three together.

5. Liver Persistent Header with changeable patterns

We saw that in the last section.SliverAppBarThe magic is that it’s based onSliverPersistentHeaderRealized. adoptSliverPersistentHeaderAnd we can do that.stickyThe effect of roof suction.

SliverPersistentHeaderThe most important attribute isSliverPersistentHeaderDelegateTo do this, we need to implement a class inheritance fromSliverPersistentHeaderDelegate

class StickyTabBarDelegate extends SliverPersistentHeaderDelegate {

  @override
  double get minExtent => null;

  @override
  double get maxExtent => null;

  @override
  bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) => null;
  
  @override
  Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) => null;
}

As you can see,SliverPersistentHeaderDelegateThe implementation class must implement its four methods. Among them:

  • minExtentThe height of the component in the retractable state;
  • maxExtentThe height of components in deployment state;
  • shouldRebuildSimilar toreactInshouldComponentUpdate
  • buildConstruct rendering content.

Next, we will implement aTabBarThe effect of roof suction.

Code (see here for the full version)

CustomScrollView(
  slivers: <Widget>[
    SliverAppBar(
      // ...
    ),
    Sliver Persistent Header (// TabBar with a ceiling)
      pinned: true,
      delegate: StickyTabBarDelegate(
        child: TabBar(
          labelColor: Colors.black,
          controller: this.tabController,
          tabs: <Widget>[
            Tab(text: 'Home'),
            Tab(text: 'Profile'),
          ],
        ),
      ),
    ),
    SliverFillRemaining (// TabBarView, the remaining supplement)
      child: TabBarView(
        controller: this.tabController,
        children: <Widget>[
          Center(child: Text('Content of Home')),
          Center(child: Text('Content of Profile')),
        ],
      ),
    ),
  ],
)

class StickyTabBarDelegate extends SliverPersistentHeaderDelegate {
  final TabBar child;

  StickyTabBarDelegate({@required this.child});

  @override
  Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) {
    return this.child;
  }

  @override
  double get maxExtent => this.child.preferredSize.height;

  @override
  double get minExtent => this.child.preferredSize.height;

  @override
  bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) {
    return true;
  }
}

Design sketch

Create interesting scrolling effects in Flutter - Sliver series

According to the figure above, we can see that below.tabAfter the content slides out of the screen,tabBarInstead of sliding along, they stick to the top. SoSliverPersistentHeaderIt does satisfy us.stickyEffect.

HoweverSliverPersistentHeaderThe magic is much more than that. ~We can customize some transitional effects of the head through it, after all.SliverAppBarIt is also through it. For example, the transition effect at the top of the movie details page below is quite common in apps.

Create interesting scrolling effects in Flutter - Sliver series

So how can this effect be achieved? The key lies inbuildIn the methodshrinkOffsetProperty, which represents the scroll offset of the current header. We can use it to calculate the current retracted head.background colorAnd icons and textFont colorSo you can get the transition effect according to the current position.~

Code (see here for the full version)

class SliverCustomHeaderDelegate extends SliverPersistentHeaderDelegate {
  final double collapsedHeight;
  final double expandedHeight;
  final double paddingTop;
  final String coverImgUrl;
  final String title;

  SliverCustomHeaderDelegate({
    this.collapsedHeight,
    this.expandedHeight,
    this.paddingTop,
    this.coverImgUrl,
    this.title,
  });

  @override
  double get minExtent => this.collapsedHeight + this.paddingTop;

  @override
  double get maxExtent => this.expandedHeight;

  @override
  bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) {
    return true;
  }

  Color makeStickyHeaderBgColor(shrinkOffset) {
    final int alpha = (shrinkOffset / (this.maxExtent - this.minExtent) * 255).clamp(0, 255).toInt();
    return Color.fromARGB(alpha, 255, 255, 255);
  }

  Color makeStickyHeaderTextColor(shrinkOffset, isIcon) {
    if(shrinkOffset <= 50) {
      return isIcon ? Colors.white : Colors.transparent;
    } else {
      final int alpha = (shrinkOffset / (this.maxExtent - this.minExtent) * 255).clamp(0, 255).toInt();
      return Color.fromARGB(alpha, 0, 0, 0);
    }
  }

  @override
  Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) {
    return Container(
      height: this.maxExtent,
      width: MediaQuery.of(context).size.width,
      child: Stack(
        fit: StackFit.expand,
        children: <Widget>[
          // Background image
          Container(child: Image.network(this.coverImgUrl, fit: BoxFit.cover)),
          // Put your head back
          Positioned(
            left: 0,
            right: 0,
            top: 0,
            child: Container(
              Color: this. makeSticky Header BgColor (shrinkOffset), // Background color
              child: SafeArea(
                bottom: false,
                child: Container(
                  height: this.collapsedHeight,
                  child: Row(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: <Widget>[
                      IconButton(
                        icon: Icon(
                          Icons.arrow_back_ios,
                          Color: this. makeStickyHeaderTextColor (shrinkOffset, true), // Return icon color
                        ),
                        onPressed: () => Navigator.pop(context),
                      ),
                      Text(
                        this.title,
                        style: TextStyle(
                          fontSize: 20,
                          fontWeight: FontWeight.w500,
                          Color: this. makeSticky Header TextColor (shrinkOffset, false), // Title color
                        ),
                      ),
                      IconButton(
                        icon: Icon(
                          Icons.share,
                          Color: this. makeSticky Header TextColor (shrinkOffset, true), // Share icon color
                        ),
                        onPressed: () {},
                      ),
                    ],
                  ),
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

Although the above code is long, most of it is built.widgetCode. So, we focus on it.makeStickyHeaderTextColorandmakeStickyHeaderBgColorAll right. Both methods are based on the current situation.shrinkOffsetThe value calculates the color value in the transition process. In addition, we need to pay attention to the head in theiPhoneXMore than Liu Haitou involved, can be usedSafeAreaComponents solve problems.

6. Summary

Firstly, this paper introducesCustomScrollViewandSliverThe concept of series components and their relationships, followed bySliverListandSliverGridAn example is given to illustrate its usage. Then, the more commonly used ones are introduced.SliverAppBarComponents, which are explained separatelyfloat/snap/pinnedTheir respective effects. Finally, it explainsSliverPersistentHeaderThe usage of components is illustrated with practical examples to illustrate the usage of their custom transition effects. Hope that through the introduction of this article, you can useCustomScrollViewandSliverSeries components create more interesting scrolling effects~

All of the code in this article is hosted here, you can also pay attention to my blog, welcome to exchange and learn together.~

Recommended Today

1. Scala language overview

Chapter 1, an overview of the Scala language == knowledge structure == Scala is divided into several stages. 1. Scala language overview 2. Basic knowledge of Scala Scala data structure Scala is object-oriented Scala functional programming 1. Scala language overview 1.1 learning tasks 1. Understand the features of Scala languageLearn to configure the Scala environmentConfigure […]