Flutter NestedScrollView使用

题记

—— 执剑天涯,从你的点滴积累开始,所及之处,必精益求精,优美的应用体验 来自于细节的处理,更源自于码农的自我要求与努力


Flutter是谷歌推出的最新的移动开发框架。

【x1】微信公众号的每日提醒 随时随记 每日积累 随心而过 文章底部扫码关注

【x2】各种系列的视频教程 免费开源 关注 你不会迷路

【x3】系列文章 百万 Demo 随时 复制粘贴 使用

【x4】五分钟视频快速带你浏览构建

【x5】一目了然的源码


如下图所示,你的APP项目中一定会应用到这样的场景。 在这里插入图片描述


以小编的性格,要实现百万Demo随时复制粘贴肯定是需要源码的

完整源码在这里

接下来一步步来实现一下,首先是小编这使用独立的一个 dart 文件作为启动入口 ,以方便 Demo 的效果实现,定义如下:

//启动函数
void main() {
  runApp(RootApp());
}

//根目录
class RootApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(primaryColor: Colors.grey[200]),
      //默认启动的页面
      home: HomePage(),
    );
  }
}
复制代码

初始化创建一个 TabController 用来控制 TabBar 与 TabBarV​iew的联动效果:​


class HomePage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return _ScrollHomePageState();
  }
}

class _ScrollHomePageState extends State with SingleTickerProviderStateMixin {

  //在这里标签页面使用的是TabView所以需要创建一个控制器
  TabController tabController;

  //页面初始化方法
  @override
  void initState() {
    super.initState();
    //初始化
    tabController = new TabController(length: 3, vsync: this);
  }

  //页面销毁回调生命周期
  @override
  void dispose() {
    tabController.dispose();
  }
  ...
}
复制代码

对于页面的主体 使用了 Scaffold :

@override
 Widget build(BuildContext context) {
   //构建页面的主体
   return Scaffold(
     //下拉刷新
     body: RefreshIndicator(
       //可滚动组件在滚动时会发送ScrollNotification类型的通知
       notificationPredicate: (ScrollNotification notifation) {
         //该属性包含当前ViewPort及滚动位置等信息
         ScrollMetrics scrollMetrics = notifation.metrics;
         if (scrollMetrics.minScrollExtent == 0) {
           return true;
         } else {
           return false;
         }
       },
       //下拉刷新回调方法
       onRefresh: () async {
         //模拟网络刷新 等待2秒
         await Future.delayed(Duration(milliseconds: 2000));
         //返回值以结束刷新
         return Future.value(true);
       },
       child: buildNestedScrollView(),
     ),
   );
 }
复制代码

RefreshIndicator 是一个下拉刷新组件,用来触发下拉刷新效果,直接嵌套NestedScrollView滑动布局来使用

//NestedScrollView 的基本使用
 Widget buildNestedScrollView() {
   //滑动视图
   return NestedScrollView(
     //配置可折叠的头布局
     headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
       return [buildSliverAppBar()];
     },
     //页面的主体内容
     body: buidChildWidget(),
   );
 }
复制代码

NestedScrollView 中包含两部分,一部分是折叠的头部,使用SliverAppBar来实现,另一部分是滑动切换的页面主体 使用 TabBarView 来实现

//通常在用到 PageView + BottomNavigationBar 或者 TabBarView + TabBar 的时候
 //大家会发现当切换到另一页面的时候, 前一个页面就会被销毁, 再返回前一页时, 页面会被重建,
 //随之数据会重新加载, 控件会重新渲染 带来了极不好的用户体验.
 //由于TabBarView内部也是用的是PageView, 因此两者的解决方式相同
 //页面的主体内容
 Widget buidChildWidget() {
   return TabBarView(
     controller: tabController,
     children: <Widget>[
       ItemPage1(1),
       ItemPage1(2),
       ItemPage1(3),
     ],
   );
 }
复制代码

SliverAppBar 的实现如下:

  //flexibleSpace可折叠的内容区域
  buildSliverAppBar() {
    return SliverAppBar(
      title: buildHeader(),
      //标题居中
      centerTitle: true,
      //当此值为true时 SliverAppBar 会固定在页面顶部
      //当此值为fase时 SliverAppBar 会随着滑动向上滑动
      pinned: true,
      //当值为true时 SliverAppBar设置的title会随着上滑动隐藏
      //然后配置的bottom会显示在原AppBar的位置
      //当值为false时 SliverAppBar设置的title会不会隐藏
      //然后配置的bottom会显示在原AppBar设置的title下面
      floating: false,
      //当snap配置为true时,向下滑动页面,SliverAppBar(以及其中配置的flexibleSpace内容)会立即显示出来,
      //反之当snap配置为false时,向下滑动时,只有当ListView的数据滑动到顶部时,SliverAppBar才会下拉显示出来。
      snap: false,
      elevation: 0.0,
      //展开的高度
      expandedHeight: 380,
      //AppBar下的内容区域
      flexibleSpace: FlexibleSpaceBar(
        //背景
        //配置的是一个widget也就是说在这里可以使用任意的
        //Widget组合 在这里直接使用的是一个图片
        background: buildFlexibleSpaceWidget(),
      ),
      bottom: buildFlexibleTooBarWidget(),
    );
  }
复制代码

SliverAppBar中有三部分,第一部分是标题部分,通过title属性配置,代码如下:

 //构建SliverAppBar的标题title
 buildHeader() {
   //透明组件
   return Container(
     width: double.infinity,
     padding: EdgeInsets.only(left: 10),
     height: 38,
     decoration: BoxDecoration(
       color: Colors.white,
       border: Border.all(color: Colors.white),
       borderRadius: BorderRadius.circular(30),
     ),
     child: Row(
       mainAxisAlignment: MainAxisAlignment.center,
       children: [
         Icon(
           Icons.search_rounded,
           size: 18,
         ),
         SizedBox(
           width: 4,
         ),
         Text(
           "搜索",
           style: TextStyle(
             fontSize: 14,
           ),
         ),
       ],
     ),
   );
 }
复制代码

第二部分就是用来折叠部分的轮播图,通过 flexibleSpace 属性配置的FlexibleSpaceBar中配置,代码如下:

buildFlexibleSpaceWidget() {
   return Column(
     children: [
       Container(
         height: 240,
         child: BannerHomepage(isTitle: false,),
       ),
       Container(
         child: Row(
           children: [
             Expanded(
               child: Container(
                 height: 120,
                 color: Colors.blueGrey,
                 child: Image.asset("images/banner5.jpeg"),
               ),
             ),
             Expanded(
               child: Container(
                 color: Colors.brown,
                 height: 120,
                 child: Image.asset("images/banner6.jpeg"),
               ),
             ),
           ],
         ),
       )
     ],
   );
 }
复制代码

BannerHomepage 轮播图的实现在这里 第三部分就是通过 bottom 配置的 TabBar 标签栏,在这里结合 PreferredSize ​来使用,代码如下:​

 //[SliverAppBar]的bottom属性配制
 Widget buildFlexibleTooBarWidget() {
   //[PreferredSize]用于配置在AppBar或者是SliverAppBar
   //的bottom中 实现 PreferredSizeWidget
   return PreferredSize(
     //定义大小
     preferredSize: Size(MediaQuery.of(context).size.width, 44),
     //配置任意的子Widget
     child: Container(
       alignment: Alignment.center,
       child: Container(
         color: Colors.grey[200],
         //随着向上滑动,TabBar的宽度逐渐增大
         //父布局Container约束为 center对齐
         //所以程现出来的是中间x轴放大的效果
         width: MediaQuery.of(context).size.width,
         child: TabBar(
           controller: tabController,
           tabs: <Widget>[
             new Tab(
               text: "标签一",
             ),
             new Tab(
               text: "标签二",
             ),
             new Tab(
               text: "标签三",
             ),
           ],
         ),
       ),
     ),
   );
 }
复制代码

以小编的性格,要实现百万Demo随时复制粘贴肯定是需要源码的

完整源码在这里

 

当然以小编的性格,肯定是要有视频录制的,点击这里查看,有兴趣 你可以关注一下 西瓜视频 --- 早起的年轻人


作者:早起的年轻人
链接:https://juejin.cn/post/6890963936368132104
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值