Flutter 滑动列表隐藏头部 ListView+TabBar悬浮的实现

先来张效果图

我的需求是,列表滚动到顶部,Tabbar停留,置顶.

实际写起来,绕了不少弯路.


最开始我使用的:

CustomScrollView

代码如下:

import 'package:flutter/material.dart';


const url =
    'http://www.pptbz.com/pptpic/UploadFiles_6909/201203/2012031220134655.jpg';

class TestPage2 extends StatefulWidget {
  @override
  _TestPage2State createState() => _TestPage2State();
}

class _TestPage2State extends State<TestPage2> {
  var tabTitle = [
    '页面1',
    '页面2',
    '页面3',
  ];

  @override
  Widget build(BuildContext context) {
    return new DefaultTabController(
        length: tabTitle.length,
        child: Scaffold(
          body: new CustomScrollView(
            slivers: <Widget>[
              new SliverAppBar(
                expandedHeight: 200.0,
                floating: true,
                pinned: true,
                flexibleSpace: FlexibleSpaceBar(
                    centerTitle: true,
                    title: Text(
                      "我是可以跟着滑动的title",
                    ),
                    background: Image.network(
                      url,
                      fit: BoxFit.cover,
                    )),
              ),
              new SliverToBoxAdapter(
                child: new TabBar(
                  tabs: tabTitle.map((f) => Tab(text: f)).toList(),
                  indicatorColor: Colors.red,
                  unselectedLabelColor: Colors.black,
                  labelColor: Colors.red,
                ),
              ),
              new SliverFillRemaining(
                child: TabBarView(
                  children: tabTitle
                      .map((s) => ListView.builder(
                            itemBuilder: (context, int) => Text("123"),
                            itemCount: 50,
                          ))
                      .toList(),
                ),
              )
            ],
          ),
        ));
  }
}



虽然列表效果出来了,但不是我想要的,

列表滑动,不会联动

使用SliverToBoxAdapter 并不会有联动效果.因为它是固定的.

想要联动,只有像NestedScrollView源码里的


使用自定义的PrimaryScrollController才行.
不过既然NestedScrollView已经做,不是特别的需求,就用NestedScrollView就好了


正确的姿势 NestedScrollView:

SliverAppBar

相当于Appbar.不过是Sliver滚动家族里的

  new SliverAppBar(
                  expandedHeight: 200.0,
                  floating: true,
                  pinned: true,
                  flexibleSpace: FlexibleSpaceBar(
                      centerTitle: true,
                      title: Text(
                        "我是可以跟着滑动的title",
                      ),
                      background: Image.network(
                        url,
                        fit: BoxFit.cover,
                      )),
                ),

悬浮最关键的:SliverPersistentHeader

这个是可以联动并且可以停留在顶部的
设置悬浮停留的属性pinned.
这里需要自己实现一个Delegate.因为需要停留weight的高度.

 new SliverPersistentHeader(
                  delegate: new SliverTabBarDelegate(
                    new TabBar(
                      tabs: tabTitle.map((f) => Tab(text: f)).toList(),
                      indicatorColor: Colors.red,
                      unselectedLabelColor: Colors.black,
                      labelColor: Colors.red,
                    ),
                    color: Colors.white,
                  ),
                  pinned: true,
                ),

最终代码:

import 'package:flutter/material.dart';

const url =
    'http://www.pptbz.com/pptpic/UploadFiles_6909/201203/2012031220134655.jpg';

class TestPage extends StatefulWidget {
  @override
  _TestPageState createState() => _TestPageState();
}

class _TestPageState extends State<TestPage> {
  var tabTitle = [
    '页面1',
    '页面2',
    '页面3',
  ];

  @override
  Widget build(BuildContext context) {
    return new DefaultTabController(
        length: tabTitle.length,
        child: Scaffold(
          body: new NestedScrollView(
            headerSliverBuilder: (context, bool) {
              return [
                SliverAppBar(
                  expandedHeight: 200.0,
                  floating: true,
                  pinned: true,
                  flexibleSpace: FlexibleSpaceBar(
                      centerTitle: true,
                      title: Text(
                        "我是可以跟着滑动的title",
                      ),
                      background: Image.network(
                        url,
                        fit: BoxFit.cover,
                      )),
                ),
                new SliverPersistentHeader(
                  delegate: new SliverTabBarDelegate(
                    new TabBar(
                      tabs: tabTitle.map((f) => Tab(text: f)).toList(),
                      indicatorColor: Colors.red,
                      unselectedLabelColor: Colors.black,
                      labelColor: Colors.red,
                    ),
                    color: Colors.white,
                  ),
                  pinned: true,
                ),
              ];
            },
            body: TabBarView(
              children: tabTitle
                  .map((s) => ListView.builder(
                        itemBuilder: (context, int) => Text("123"),
                        itemCount: 50,
                      ))
                  .toList(),
            ),
          ),
        ));
  }
}

class SliverTabBarDelegate extends SliverPersistentHeaderDelegate {
  final TabBar widget;
  final Color color;

  const SliverTabBarDelegate(this.widget, {this.color})
      : assert(widget != null);

  @override
  Widget build(
      BuildContext context, double shrinkOffset, bool overlapsContent) {
    return new Container(
      child: widget,
      color: color,
    );
  }

  @override
  bool shouldRebuild(SliverTabBarDelegate oldDelegate) {
    return false;
  }

  @override
  double get maxExtent => widget.preferredSize.height;

  @override
  double get minExtent => widget.preferredSize.height;
}

最终效果

题外话:

如果不使用TabBar+TabBarView
那么直接使用CustomScrollView就可以了.
使用SliverList代替ListView就可以进行联动.


期待你的留言交流.

交流群: 782978118(flutter群) 493180098 (android群)

flutter开源项目地址:https://github.com/Jlanglang/yiball

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章