Zero, preface,

If you’ve ever been to FlutterUnit, the Tap bar in the header of the home page should have impressed you. The Tap bar becomes progressively shorter as you slide up to a minimum. When the Tap bar is pulled down to the top, the Tap bar becomes progressively higher until the maximum value FlutterUnit itself has a complex home page. In this article, I will write a minimalist practice that uses the least amount of code to achieve this effect. SliverPersistentHeader

Slide effect The drop-down effect

I. Initial project

1. Program entry

In the main function using SystemChrome. SetSystemUIOverlayStyle make the status bar is transparent

Core components in SliverPersistentHeaderDemo test demo

void main() {
  // Set the transparent status bar
  SystemUiOverlayStyle style = SystemUiOverlayStyle(statusBarColor: Colors.transparent);
  SystemChrome.setSystemUIOverlayStyle(style);
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Flutter Demo',
        debugShowCheckedModeBanner: false, theme: ThemeData( primarySwatch: Colors.blue ), home: Scaffold( body: SliverPersistentHeaderDemo(), )); }}Copy the code

2. Build a color list

We’re going to build a more sophisticated sliding effect, using a CustomScrollView where slivers receive a list of Sliver family components. CustomScrollView is not the subject of this article, but will be covered later. _buildSliverList is responsible for building SliverList, where the buildColor item component is left to _buildColorItem. I recommend that you break down the granularity of your build, rather than trying to put everything in one piece, so it looks clearer.

Color list Color list
class SliverPersistentHeaderDemo extends StatelessWidget {
	// Color data
  final List<Color> data = List.generate(24, (i) => Color(0xFFFF00FF - 24*i));

  @override
  Widget build(BuildContext context) {
    return CustomScrollView(
        slivers: <Widget>[
          // TODO adds bar
          _buildSliverList()
        ],
    );
  }

  // Build a list of colors
  Widget _buildSliverList() =>
      SliverList(
        delegate: SliverChildBuilderDelegate(
                (_, int index) => _buildColorItem(data[index]),
            childCount: data.length),
      );

	// Build the color list item
  Widget _buildColorItem(Color color) =>
      Card(
        child: Container(
          alignment: Alignment.center,
          width: 100,
          height: 60,
          color: color,
          child: Text(
            colorString(color),
            style: const TextStyle(
                color: Colors.white,
                shadows: [
                  Shadow(color: Colors.black,
                      offset: Offset(. 5.. 5),
                      blurRadius: 2() [(), ((), (();// Color is converted to text
  String colorString(Color color) =>
      "#${color.value.toRadixString(16).padLeft(8.'0').toUpperCase()}";
}
Copy the code

Now that the initial demo is set up, let’s see how SliverPersistentHeader is used


Second, knowSliverPersistentHeader

1.SliverPersistentHeaderProperties in
The property name type The default value introduce
delegate SliverPersistentHeaderDelegate required Component build agent
pinned bool false Whether fixed
floating bool false Whether floating

2.SliverPersistentHeaderDelegateThe use of

I’m sure a lot of people look at XXXDelegate and feel dissuaded. Don’t be afraid. Let’s see what it is. We can see that it’s an abstract class, so we need to implement some abstract method, and an abstract method is always going to call back something of value and look at its family tree and see that there’s no subclass that we can use, so if we want to use it, we need to write a subclass.

Now write a UnitPersistentHeaderDelegate implement SliverPersistentHeaderDelegate, can see there are the following four methods: need to implement build,maxExtent,minExtent,shouldRebuild

class UnitPersistentHeaderDelegate extends SliverPersistentHeaderDelegate {
  @override
  Widget build(
      BuildContext context, double shrinkOffset, bool overlapsContent) {
    print(
        "=====shrinkOffset:$shrinkOffset======overlapsContent:$overlapsContent= = = =");
    final String info =
        'shrinkOffset:${shrinkOffset.toStringAsFixed(1)}'
        '\noverlapsContent:$overlapsContent';
    return Container(
      alignment: Alignment.center,
      color: Colors.orangeAccent,
      child: Text(
        info,
        style: TextStyle(fontSize: 20, color: Colors.white),
      ),
    );
  }
  @override
  double get maxExtent => 120;
  
  @override
  double get minExtent => 80;
  
  @override
  bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) =>
      false;
}
Copy the code

Give me a little simple implementation using the above definition of UnitPersistentHeaderDelegate view effect: As you can see, the build method above is used to build components with shrinkOffset in the header. The components begin to expand the maxExtent height fully as they slide up the list. You can see from the log that the maximum slide height is maxExtent, which is the default pinned=false,floating=false slide effect.

Slide the test The tensile test
    // The hero sees...
    return CustomScrollView(
      slivers: <Widget>[
        _buildPersistentHeader(), PersistentHeader is created above the list
        _buildSliverList()
      ],
    );
  }
	
  / / use UnitPersistentHeaderDelegate PersistentHeader creation
  Widget _buildPersistentHeader() => SliverPersistentHeader(
      delegate: UnitPersistentHeaderDelegate());

Copy the code

3. SliverPersistentHeaderPinned with floatingattribute

Here’s the test:

pinned_true_floating_false pinned_true_floating_true
Skidding up: The minExtent height is left at the top and does not decrease with skidding up Skidding up: The minExtent height is left at the top and does not decrease with skidding up
Pull down: The remaining space does not unfold until you reach the top Drop down: When you drop down from any position, the remaining space expands

Here’s the test:

pinned_false_floating_false pinned_false_floating_true
Slide up: The top slides out Slide up: The top slides out
Pull down: The top does not unfold until you reach the top Drop down: Space expands when you drop down from any position

Three, use,SliverPersistentHeader

1. Wrap PersistentHeaderBuilder

The persistenThebuilder is a custom builder that simplifies the build

Using the Builder property, you can call back some valuable data, such as offsets, when you hand over the created logic to use

class PersistentHeaderBuilder extends SliverPersistentHeaderDelegate {
  final double max;
  final double min;
  final Widget Function(BuildContext context, double offset) builder;

  PersistentHeaderBuilder(
      {this.max = 120.this.min = 80.@required this.builder})
      : assert(max >= min && builder ! =null);

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

  @override
  double get maxExtent => max;

  @override
  double get minExtent => min;

  @override
  bool shouldRebuild(covariantPersistentHeaderBuilder oldDelegate) => max ! = oldDelegate.max || min ! = oldDelegate.min || builder ! = oldDelegate.builder; }Copy the code

2. Use PersistentHeaderBuilder
  Widget _buildPersistentHeader() => SliverPersistentHeader(
      pinned: true,
      floating: false,
      delegate: PersistentHeaderBuilder(builder: (ctx, offset) => Container(
        alignment: Alignment.center,
        color: Colors.orangeAccent,
        child: Text(
          "shrinkOffset:${offset.toStringAsFixed(1)}",
          style: TextStyle(fontSize: 20, color: Colors.white),
        ),
      )));
Copy the code

3. Use of multiple SliverPersistentHeader

You can also do some transformations based on offset. Multiple SliverPersistentHeader can coexist, as shown below

slide The drop-down
Widget _buildPersistentHeader2() => SliverPersistentHeader(
    pinned: false,
    floating: false,
    delegate: PersistentHeaderBuilder(
        max: 100,
        builder: (ctx, offset) => Container(
              transform: Matrix4.rotationZ(offset / 120 * pi / 2),
              alignment: Alignment.center,
              color: Colors.blue,
              child: Text(
                "shrinkOffset:${offset.toStringAsFixed(1)}",
                style: TextStyle(fontSize: 20, color: Colors.white),
              ),
            )));
Copy the code

This is the basic usage of SliverPersistentHeader, and you can achieve many interesting sliding effects based on it. Finally, welcome to my open source project FlutterUnit. There will be more articles about FlutterUnit, including the use of Flutter components. FlutterUnit implementation details, major updates to FlutterUnit, etc.

@Zhangfengjietele 2020.10.25 not allowed to transfer ~ END ~