30 Flutter NestedScrollView

NestedScrollView

1.简介

在滑动中,ScrollView与ListView以及TabBarView,会出现滑动冲突,该控件是用于解决滑动冲突的,与CustomScrollView类似,但是不同点在于
CustomScrollView 要全部是Sliver家族的,其中TabBarView不属于Sliver家族,导致CustomScrollView 无法实现该功能,所以有了NestedScrollView

2.说明

NestedScrollView当中,有2个ScrollController.一个是inner,一个outer。 outer是负责headerSliverBuilder里面的滚动widgets inner是负责body里面的滚动widgets 当outer滚动到底了之后,就会看看inner里面是否有能滚动的东东,开始滚动
Tabview是在body里面,这里我们肯定需要对inner进行处理。 首先我们要明白,NestedScrollView是怎么处理outer和inner的关系的。

3.属性

   Key key,
    this.controller,
    this.scrollDirection = Axis.vertical,  方向
    this.reverse = false,
    this.physics,   //可以指定滑动方式 NeverScrollableScrollPhysics 不滑动
    @required this.headerSliverBuilder,     outer
    @required this.body,		inner
    this.dragStartBehavior = DragStartBehavior.start,  
    this.floatHeaderSlivers = false,
    this.clipBehavior = Clip.hardEdge,
    this.restorationId,

4.案例 实现一个类似 AppBarLayout+CollapsingToolbarLayout + listView的效果

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      // home: CustomScrollViewDemo(),
      home: Scaffold(
        body: NestedScrollViewDemo2(),
      ),
    );
  }
}

class NestedScrollViewDemo2 extends StatefulWidget {
  NestedScrollViewDemo2({Key key}) : super(key: key);

  @override
  _NestedScrollViewDemo2State createState() {
    return _NestedScrollViewDemo2State();
  }
}

class _NestedScrollViewDemo2State extends State<NestedScrollViewDemo2> {
  @override
  void initState() {
    super.initState();
  }

  @override
  void dispose() {
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return NestedScrollView(
      scrollDirection:  Axis.vertical,
      headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
        return <Widget>[
          SliverAppBar(
            expandedHeight: 200.0,
            pinned: true,
            flexibleSpace: FlexibleSpaceBar(
              title: Text('复仇者联盟'),
              background: Container(
                color: Colors.blue[300],
                height: 200,
                width: double.infinity,
                child: Image.network(
                  'http://img.haote.com/upload/20180918/2018091815372344164.jpg',
                  fit: BoxFit.cover,
                  height: 200,
                ),
              ),
            ),
          )
        ];
      },
      body: ListView.builder(
        itemBuilder: (BuildContext context, int index) {
          return Container(
            height: 80,
            // color: Colors.primaries[index % Colors.primaries.length],
            color: Colors.yellow,
            alignment: Alignment.center,
            child: Text(
              '$index',
              style: TextStyle(color: Colors.blue, fontSize: 20),
            ),
          );
        },
        itemCount: 20,
      ),

      // body: Container(
      //   height: 200,
      //   color: Colors.red,
      // ),

    );
  }
}

注意:ListView头部有一段空白区域,是因为当ListView没有和AppBar一起使用时,头部会有一个padding,为了去掉padding,可以使用MediaQuery.removePadding 包裹这个ListView

      body: MediaQuery.removePadding(
        removeTop: true,
        context: context,
        child: ListView.builder(
          itemBuilder: (BuildContext context, int index) {
            return Container(
              height: 80,
              // color: Colors.primaries[index % Colors.primaries.length],
              color: Colors.yellow,
              alignment: Alignment.center,
              child: Text(
                '$index',
                style: TextStyle(color: Colors.blue, fontSize: 20),
              ),
            );
          },
          itemCount: 20,
        ),
      ),

5.NestedScrollView + TabBarView结合使用

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      // home: CustomScrollViewDemo(),
      home: Scaffold(
        body: NetScrollHomePage(),
      ),
    );
  }
}

class NetScrollHomePage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return ScrollHomePageState();
  }
}

class ScrollHomePageState extends State with SingleTickerProviderStateMixin {
  TabController tabController;

  @override
  void initState() {
    super.initState();

    ///这里的 3 代表有三个子 Item
    ///应用到 TabBarView 中,对应其中3个子Item
    ///应用到 TabBar中,对应其中32上子Item
    tabController = new TabController(length: 3, vsync: this);
  }

  TabBar buildTabBar() {
    return TabBar(
      controller: tabController,
      tabs: <Widget>[
        new Tab(
          text: "标签一",
        ),
        new Tab(
          text: "标签二",
        ),
        new Tab(
          text: "标签三",
        ),
      ],
    );
  }

  String imageUrl =
      'http://img.haote.com/upload/20180918/2018091815372344164.jpg';

  FlexibleSpaceBar buildFlexibleSpaceBar() {
    return FlexibleSpaceBar(
//                title: Text("FlexibleSpaceBar title"),
      centerTitle: true,
      background: Container(
        color: Colors.blue[300],
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: <Widget>[
            Container(
              height: 150,
              child: Image.network(
                imageUrl,
                fit: BoxFit.fill,
                height: 160,
                width: 400,
              ),
            ),
          ],
        ),
      ),
    );
  }

  NestedScrollView buildNestedScrollView() {
    return NestedScrollView(
      headerSliverBuilder: (BuildContext context, bool b) {
        return [
          SliverAppBar(
            ///true SliverAppBar 不会滑动
            pinned: true,

            ///是否随着滑动隐藏标题
            floating: true,

            ///SliverAppBar展开的高度
            expandedHeight: 200,
            flexibleSpace: buildFlexibleSpaceBar(),
            bottom: buildTabBar(),
          ),
          SliverToBoxAdapter(
            child: Container(
              width: double.infinity,
              height: 200,
              color: Colors.red,
            ),
          ),
        ];
      },

      ///主体部分
      body: buildTabBarView(),
    );
  }

  TabBarView buildTabBarView() {
    return TabBarView(
      controller: tabController,
      children: <Widget>[
        SingleChildScrollView(
          child: Container(
            alignment: Alignment.bottomLeft,
            child: Text("这是第一个页面"),
            height: 1000,
          ),
        ),
        Text(
          "这是第二个页面",
          style: TextStyle(color: Colors.blue),
        ),
        Text(
          "这是第三个页面",
          style: TextStyle(color: Colors.red),
        ),
      ],
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: new AppBar(
        title: Text(" 配制"),
      ),

      /// 处理滑动
      body: buildNestedScrollView(),
    );
  }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值