Flutter 页面上滑,AppBar吸附效果

2,089 阅读2分钟

先上效果图!

    注: 红色块:整体背景,每一个颜色为一块内容,大家在`SliverToBoxAdapter`替换成自己的内容就好.

1.使用NestedScrollView进行滑动效果的制作. 使用 NestedScrollView对body进行第一层的使用,代码如下:

@override
  Widget build(BuildContext context) {
    return Scaffold(
      body: NestedScrollView(
        headerSliverBuilder: (context, innerBoxIsScrolled) {
          return <Widget>[
            SliverOverlapAbsorber(
              handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
              child: _buildAppbarView(context, innerBoxIsScrolled), // 吸附的AppBar
            )
          ];
        },
        body: _buildBodyView(), // AppBar下面的内容区域
      ),
    );
  }

2.然后,实现AppBar,代码如下:

/// AppBar
 Widget _buildAppbarView(context, bool innerBoxIsScrolled) {
    return SliverAppBar(
      pinned: true, // 吸附
      centerTitle: true,
      forceElevated: innerBoxIsScrolled,
      expandedHeight: 140, // AppBar的高度
      title: Text("这是标题"), // 标题,title参数接收的是一个Widget,可灵活使用.
      backgroundColor: Colors.orangeAccent,
      leading: Container(), // 占位,可删.
      flexibleSpace: FlexibleSpaceBar( // 可伸缩属性,这里是重点
        background: Container(      // background接收的是这个Widget,可以使用Stack进行灵活的布局
          height: 100,
          child: Container(
            height: 100,
            color: Colors.red.shade200,
          ),
        ),
      ),
    );
  }

3.再然后,实现body内容区域,代码如下:

Widget _buildBodyView() {
    return SafeArea(
      top: true,
      child: Container(
        margin: EdgeInsets.only(top: kToolbarHeight),
        color: Colors.red,
        child: CustomScrollView(
          slivers: <Widget>[
            SliverToBoxAdapter(
                child: Container(
              height: 150,
              color: Colors.blue.shade200,
              child: Center(child: Text('我是内容')
                  // child: _carousel(), // 这里就是我的内容,同下
                  ),
            )),
            SliverToBoxAdapter(
                child: Container(
              height: 50,
              color: Colors.green.shade200,
              child: Center(child: Text('我是内容')
                  // child: _buildMessage(),
                  ),
            )),
            SliverToBoxAdapter(
                child: Container(
              height: 50,
              color: Colors.orange.shade200,
              child: Center(child: Text('我是内容')
                  // child: _expandableWrap(),
                  ),
            )),
            SliverToBoxAdapter(
                child: Container(
              height: 150,
              color: Colors.pink.shade200,
              child: Center(child: Text('我是内容')
                  // child: _buildVideoAndBookEntry(),
                  ),
            )),
            SliverToBoxAdapter(
                child: Container(
              height: 150,
              color: Colors.pink.shade200,
              child: Center(child: Text('我是内容')
                  // child: _buildTopicTalkTwo(),
                  ),
            )),
          ],
        ),
      ),
    );
  }

记另一种写法: 只不过有个问题是: 当内容不够一屏时,无法滑动到你想要的位置,但还算合理吧.

@override
  Widget build(BuildContext context) {
    return Scaffold(
      body: _buildScaffoldBody()
    );
  }
Widget _buildScaffoldBody() {
    return CustomScrollView(
      slivers: <Widget>[
        SliverAppBar(
          expandedHeight: 120,
          pinned: true,
          title: Text('环境执法实务'),
          flexibleSpace: FlexibleSpaceBar(
            collapseMode: CollapseMode.parallax,
            background: Stack(
              children: <Widget>[
                Container(
                  decoration: BoxDecoration(
                      image: DecorationImage(
                          image: AssetImage(
                              'lib/asset/images/home_share_gift_bg.png'),
                          fit: BoxFit.cover)),
                  child: SafeArea(
                    top: true,
                    child: Column(
                      children: <Widget>[
                        Container(
                            height: 50,
                            child: Text('',
                                style: TextStyle(
                                    color: Colors.white, fontSize: 20))),
                        SearchInputWidget(
                          hasRightIcon: true,
                          text: '环境法规大全',
                          bgc: Colors.transparent,
                          icon1: Icons.bookmark,
                          icon2: Icons.add,
                          onTap: () => Navigator.pushNamed(context, '/search'),
                        ),
                      ],
                    ),
                  ),
                )
              ],
            ),
          ),
          // title: ,
        ),
        SliverToBoxAdapter(
          child: Column(
            children: <Widget>[
              _carousel(),
              _buildMessage(),
              _expandableWrap(),
              _buildVideoAndBookEntry(),
              _buildTopicTalkTwo(),
            ],
          ),
        )
      ],
    );
  }

仅为自己的一些想法,如果同学有更好的方法,欢迎在下面留言打扰~