Flutter 滚动组件ListView,GridView,Sliver以及滚动监听

news2024/11/25 10:26:48

前言

身是菩提树  心是明镜台 时时勤拂拭 模式染尘埃

这玩意不难,就是东西多。。。

1 看一下继承关系

class GridView extends BoxScrollView

abstract class BoxScrollView extends ScrollView

abstract class ScrollView extends StatelessWidget

 

2 下面是scroll_view.dart 中的代码

这个注释就是很清楚了 ,子类就是要重写buildSlivers这个方法,这是个抽象的方法。

  /// Build the list of widgets to place inside the viewport.
  ///
  /// Subclasses should override this method to build the slivers for the inside
  /// of the viewport.
  @protected
  List<Widget> buildSlivers(BuildContext context);

这是BoxScrollView 中 buildSlivers 的实现方法

  @override
  List<Widget> buildSlivers(BuildContext context) {
    Widget sliver = buildChildLayout(context);
    EdgeInsetsGeometry? effectivePadding = padding;
    if (padding == null) {
      final MediaQueryData? mediaQuery = MediaQuery.maybeOf(context);
      if (mediaQuery != null) {
        // Automatically pad sliver with padding from MediaQuery.
        final EdgeInsets mediaQueryHorizontalPadding =
            mediaQuery.padding.copyWith(top: 0.0, bottom: 0.0);
        final EdgeInsets mediaQueryVerticalPadding =
            mediaQuery.padding.copyWith(left: 0.0, right: 0.0);
        // Consume the main axis padding with SliverPadding.
        effectivePadding = scrollDirection == Axis.vertical
            ? mediaQueryVerticalPadding
            : mediaQueryHorizontalPadding;
        // Leave behind the cross axis padding.
        sliver = MediaQuery(
          data: mediaQuery.copyWith(
            padding: scrollDirection == Axis.vertical
                ? mediaQueryHorizontalPadding
                : mediaQueryVerticalPadding,
          ),
          child: sliver,
        );
      }
    }

    if (effectivePadding != null) {
      sliver = SliverPadding(padding: effectivePadding, sliver: sliver);
    }
    return <Widget>[sliver];
  }

从下面这行代码可以看出来,BoxScrollView 只有一个Sliver

Widget sliver = buildChildLayout(context);

而这个Sliver 来自调用 buildChildLayout,同时这个方法又是一个未实现的抽象方法,所以那么需要子类去实现这个方法,那么换言之1就是 Gridview 和 Listview 去实现这个方法

这个就是GridView 中实现的方法,返回的是一个SliverGrid 本质是也是一个

 @override
  Widget buildChildLayout(BuildContext context) {
    return SliverGrid(
      delegate: childrenDelegate,
      gridDelegate: gridDelegate,
    );
  }

 这是 ListView 的实现的方法

Widget buildChildLayout(BuildContext context) {
    if (itemExtent != null) {
      return SliverFixedExtentList(
        delegate: childrenDelegate,
        itemExtent: itemExtent!,
      );
    } else if (prototypeItem != null) {
      return SliverPrototypeExtentList(
        delegate: childrenDelegate,
        prototypeItem: prototypeItem!,
      );
    }
    return SliverList(delegate: childrenDelegate);
  }

一 ListView

1 第一种构造方法

ListView()

 ListView(
      padding: EdgeInsets.all(10),
      itemExtent: 100,
      children: List.generate(100, (index) {
        return Text("data--${index}");
      }),
    );

2 第二种构造方法

ListView.builder

_demo2() {
    return ListView.builder(
      itemExtent: 100,
      itemBuilder: (context, index) {
        return Text("data");
      },
    );
  }

3 第三种构造方法

ListView.separated

 _demo3() {
    return ListView.separated(
        itemBuilder: (context, index) {
          return Text("data---${index}");
        },
        separatorBuilder: (context, index) {
          // 返回分割的区域 thickness 为线高
          return Divider(
            color: Colors.redAccent,
            height: 10,
            thickness: 10,
          );
        },
        itemCount: 100);
  }

 

二  GridView

网格布局

1 第一种构造方法

demo1() {
    return GridView(
        padding: EdgeInsets.only(left: 10, right: 10),
        gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
            // 交叉轴的间距
            crossAxisSpacing: 10,
            // 主轴的间距
            mainAxisSpacing: 10,
            // 宽高比
            childAspectRatio: 16 / 18,
            // 交叉轴的个数
            crossAxisCount: 3),
        children: List.generate(100, (index) {
          return Container(
            color: Color.fromARGB(255, Random().nextInt(256),
                Random().nextInt(256), Random().nextInt(256)),
          );
        }));
  }

2 第二种构造方法

 _demo2() {
    return GridView.builder(
      gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
        crossAxisCount: 3,
        childAspectRatio: 1 / 1,
        mainAxisSpacing: 10,
        crossAxisSpacing: 8,
      ),
      itemBuilder: (context, index) {
        return Container(
          color: Color.fromARGB(255, Random().nextInt(256),
              Random().nextInt(256), Random().nextInt(256)),
        );
      },
    );
  }

3 第三种构造方法

  _demo3() {
    return GridView.count(
        mainAxisSpacing: 10,
        crossAxisSpacing: 10,
        crossAxisCount: 3,
        children: List.generate(100, (index) {
          return Container(
            color: Color.fromARGB(255, Random().nextInt(256),
                Random().nextInt(256), Random().nextInt(256)),
          );
        }));
  }

 

三 Slivers

这个单词翻译成 碎片,可以将一个独立的滚动视图当做一个小裂片来使用。

这个主要是实现一些复杂的布局。

  • SliverList:类似于我们之前使用过的ListView;

  • SliverFixedExtentList:类似于SliverList只是可以设置滚动的高度;

  • SliverGrid:类似于我们之前使用过的GridView;

  • SliverPadding:设置Sliver的内边距,因为可能要单独给Sliver设置内边距;

  • SliverAppBar:添加一个AppBar,通常用来作为CustomScrollView的HeaderView;

  • SliverSafeArea:设置内容显示在安全区域(比如不让齐刘海挡住我们的内容)

示例一

放置多个滚动组件在里面。

_demo1() {
    return CustomScrollView(
      // 设置内边距
      slivers: [
        // // 第一个部分
        SliverPadding(
          padding: EdgeInsets.all(8),
          sliver: SliverSafeArea(
              // 这个安全区域可以设置上下左右
              bottom: false,
              sliver: SliverGrid(
                  gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                      crossAxisCount: 3,
                      crossAxisSpacing: 8,
                      mainAxisSpacing: 8,
                      childAspectRatio: 16 / 18),
                  delegate: SliverChildBuilderDelegate(((context, index) {
                    return Container(
                      color: Color.fromARGB(255, Random().nextInt(256),
                          Random().nextInt(256), Random().nextInt(256)),
                    );
                  }), childCount: 6))),
        ),

        // 第二个部分
        SliverGrid(
            gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                crossAxisCount: 2,
                crossAxisSpacing: 8,
                mainAxisSpacing: 8,
                childAspectRatio: 16 / 18),
            delegate: SliverChildBuilderDelegate(((context, index) {
              return Container(
                color: Color.fromARGB(255, Random().nextInt(256),
                    Random().nextInt(256), Random().nextInt(256)),
              );
            }),
                // 一共多少个item
                childCount: 2)),

        //  第三个部分
        SliverGrid(
            gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                crossAxisCount: 4,
                crossAxisSpacing: 8,
                mainAxisSpacing: 8,
                childAspectRatio: 16 / 18),
            delegate: SliverChildBuilderDelegate(((context, index) {
              return Container(
                color: Color.fromARGB(255, Random().nextInt(256),
                    Random().nextInt(256), Random().nextInt(256)),
              );
            }),
                // 一共多少个item
                childCount: 40)),
      ],
    );
  }

 

示例2

这里还可以设置一个SliverAppBar, 设置很多属性

 _demo2() {
    return CustomScrollView(
      slivers: [
        // 用这个导航 上面的导航就可以删掉 这个导航可以随着内容滚动而滚动
        SliverAppBar(
          // 扩展一个高度 设置一个图片
          expandedHeight: 200,
          flexibleSpace: FlexibleSpaceBar(
              title: Text("Helo"),
              background: Image.asset(
                "images/movie_1.png",
                fit: BoxFit.cover,
              )),

          // 是否随着内容滚动
          pinned: true,
        ),
        // 第一个是SliverGrid
        SliverPadding(
          padding: EdgeInsets.all(8),
          sliver: SliverGrid(
            delegate: SliverChildBuilderDelegate(((context, index) {
              return Container(
                color: Color.fromARGB(255, Random().nextInt(256),
                    Random().nextInt(256), Random().nextInt(256)),
              );
            }), childCount: 3),
            gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                crossAxisCount: 3,
                mainAxisSpacing: 8,
                crossAxisSpacing: 8,
                childAspectRatio: 1 / 1),
          ),
        ),
        // 第二个使用SliverList
        SliverList(
            delegate: SliverChildBuilderDelegate((context, index) {
          return ListTile(
            leading: Icon(Icons.phone),
            title: Text("第---${index}-----行"),
          );
        }, childCount: 100))
      ],
    );
  }

 

 

四 滚动监听

1 使用controller 进行监听

不管我们用ListView 还是GridView  还是CustomScrollView,

都有一个controller 属性

class _SWListenDemoState extends State<SWListenDemo> {
  // 设置一个controller
  ScrollController _controller = ScrollController(initialScrollOffset: 100);

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    // 回到顶部可以 调用的方法
    // _controller.animateTo(0, duration: Duration(seconds: 2), curve: Curves.bounceIn);
    _controller.addListener(() {
      // 监听滚动的位置
      print("${_controller.offset}");
    });
  }

2 NotificationListener

如果我们希望监听什么时候开始滚动,什么时候结束滚动,这个时候我们可以通过NotificationListener

class NotificationListener<T extends Notification> extends ProxyWidget

  • NotificationListener是一个Widget,模板参数T是想监听的通知类型,如果省略,则所有类型通知都会被监听,如果指定特定类型,则只有该类型的通知会被监听。

  • NotificationListener需要一个onNotification回调函数,用于实现监听处理逻辑。

  • 该回调可以返回一个布尔值,代表是否阻止该事件继续向上冒泡,如果为true时,则冒泡终止,事件停止向上传播,如果不返回或者返回值为false 时,则冒泡继续。

Widget build(BuildContext context) {
    return NotificationListener(
        onNotification: (ScrollStartNotification notification) {
          // 当前滚动的位置 和 总长度
          final currentPixels = notification.metrics.pixels;
          final totalPixels = notification.metrics.maxScrollExtent;
          double progress = currentPixels / totalPixels;
          print("开始滚动了.....${progress} -- ${currentPixels}");

          return false;
        },
        child: ListView(
          // controller: _controller,
          children: List.generate(100, (index) {
            return ListTile(
              leading: Icon(Icons.time_to_leave),
              title: Text("---DiDi---"),
            );
          }),
        ));
     
  }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/425949.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

set和map

set和map关联式容器键值对树状结构关联式容器set介绍使用multiset介绍使用map介绍使用multimap介绍使用底层容器AVL树概念操作节点定义插入旋转红黑树&#xff08;RBTree&#xff09;概念节点的设计迭代器的设计结构插入红黑树模拟实现set与map模拟实现map模拟实现set关联式容器…

【Java 数据结构】单向链表和双向链表的实现 (LinkedList)

&#x1f389;&#x1f389;&#x1f389;点进来你就是我的人了 博主主页&#xff1a;&#x1f648;&#x1f648;&#x1f648;戳一戳,欢迎大佬指点!人生格言&#xff1a;当你的才华撑不起你的野心的时候,你就应该静下心来学习! 欢迎志同道合的朋友一起加油喔&#x1f9be;&am…

android studio 页面布局(2)

<?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"xmlns:app"http://schemas.android.com/apk/res-auto"xmlns:tools"http://schemas.android.com/too…

【数据挖掘与商务智能决策】第九章 随机森林模型

9.1.3 随机森林模型的代码实现 和决策树模型一样&#xff0c;随机森林模型既可以做分类分析&#xff0c;也可以做回归分析。 分别对应的模型为随机森林分类模型&#xff08;RandomForestClassifier&#xff09;及随机森林回归模型&#xff08;RandomForestRegressor&#xff…

Vue.js 2.0 组件

什么是组件&#xff1f; 组件&#xff08;Component&#xff09;是 Vue.js 最强大的功能之一。组件可以扩展 HTML 元素&#xff0c;封装可重用的代码。在较高层面上&#xff0c;组件是自定义元素&#xff0c; Vue.js 的编译器为它添加特殊功能。在有些情况下&#xff0c;组件也…

《花雕学AI》19:比较ChatGPT与新Bing在文章润色方面的应用优势与测试案例

引言&#xff1a; 文章润色是指对已经写好的文章进行修改、优化或完善的过程&#xff0c;以提高文章的质量和效果。文章润色涉及到多方面的内容&#xff0c;如语言表达、逻辑结构、文献引用、格式规范等。文章润色对于提升写作水平、提高论文发表率、增加学术影响力等都有重要意…

JavaScript【趣味】做一个网页版2048

文章目录&#x1f31f;前言&#x1f31f;先看效果&#xff08;粉丝特权哈哈&#xff09;&#x1f31f;代码实现&#x1f31f;页面布局 【index.html】&#x1f31f;样式文件【2048.css】&#x1f31f;index.html 里用到的JS文件&#x1f31f;jquery.min.js&#x1f31f;util.js…

300元左右的蓝牙耳机哪个好?300左右音质最好的蓝牙耳机

无线耳机是人们日常生活中必不可少的设备&#xff0c;无论是听音乐化石看电影都能获得身临其境的感觉&#xff0c;由于科技真在发展中&#xff0c;不断地的发生变化&#xff0c;百元价位就可以感受到不错的音色&#xff0c;下面小编整理了几款300左右音质表现不错的蓝牙耳机。 …

Linux 、Android将在汽车舞台上开战

导读在 CES 2017 上&#xff0c;AGL 宣布&#xff0c;Mercedes-Benz 的母公司 Daimler 正式加入。这是第十家汽车制造商加入 AGL&#xff0c;也是第一家德国公司加入 AGL。AGL&#xff08;Automotive Grade Linux&#xff09;&#xff0c;是 Linux 基金会的一个相互协作的开源组…

mallox勒索病毒数据恢复|金蝶、用友、管家婆、OA、速达、ERP等软件数据库恢复

目录 前言&#xff1a; 一、mallox勒索病毒及xollam勒索病毒的特点 二、mallox勒索病毒及xollam勒索病毒的影响 三、mallox勒索病毒及xollam勒索病毒数据恢复服务 四、mallox勒索病毒及xollam勒索病毒加密数据库恢复案例 五、以下是预防mallox勒索病毒及xollam勒索病毒安全…

解读CANDT测试项-采样点测试

原标题&#xff1a;解读CANDT测试项-采样点测试 一、为什么要进行采样点测试&#xff1f; 本文引用地址&#xff1a;http://www.eepw.com.cn/article/202004/411611.htm 为了保证有效的通信&#xff0c;对于一个只有两个节点的CAN网络&#xff0c;其两边距离不超过最大的传输…

day12 共享内存(内存映射的使用、注意事项、进程间通信、systemV共享内存)

内存映射的基本使用 概念&#xff1a; 功能共享内存可以通过mmap&#xff08;&#xff09;映射普通文件。 是一个磁盘文件与内存中的一个缓冲区相映射&#xff0c;进程可以像访问普通内存一样对文件进行访问&#xff0c;不必在调用read 、write。 mmap&#xff08;&#xf…

ChatGPT 与 MindShow 一分钟搞定一个PPT

前言 PPT制作是商务、教育和各种场合演讲的重要组成部分。然而&#xff0c;很多人会花费大量时间和精力在内容生成和视觉设计方面。为了解决这个问题&#xff0c;我们可以利用两个强大的工具——ChatGPT和MindShow&#xff0c;来提高制作PPT的效率。 一、ChatGPT 与 MindShow…

JUC-01 线程的创建和状态转换

本次我们主要讲三个问题 线程是什么&#xff1f;线程有哪些状态&#xff1f;各状态间的转换了解吗&#xff1f;创建线程的3种方法你都了解吗&#xff1f; 1. 线程是什么&#xff1f;&#xff08;了解即可&#xff09; 进程&#xff1a; 进程是一个具有一定独立功能的程序在一…

四次挥手刨根问底19问详解,全网最全

1.请描述一下TCP连接的四次挥手过程&#xff1f; 回答&#xff1a;TCP连接的四次挥手过程包括以下步骤&#xff1a; 步骤1&#xff1a;客户端向服务器端发送一个FIN报文段&#xff0c;请求关闭连接。 步骤2&#xff1a;服务器端收到FIN报文段后&#xff0c;向客户端发送一个…

python列表,元组和字典

1、python列表 1.1.列表的定义 list是一种有序的集合、基于 链表实现,name[ ] ,全局定义:list2list([ ])。 1.2下标索引 python不仅有负索引也有正索引。正索引从0开始,负索引从-1开始。这两个可以混用,但指向还是那个位置 a[0]a[-9]//length为10的数组a1.3列表的切片 列表可…

navicat如何使用orcale(详细步骤)

目录前言操作1.连接数据库2.建库问题总结前言 看过我昨天文章的兄弟姐妹都知道最近接手另一个国企项目&#xff0c;数据库用的是orcale。实话实说&#xff0c;也有快三年没用过orcale数据库了。 这期间问题不断&#xff0c;因为orcale日渐消沉&#xff0c;网上资料也是真真假…

UE4 回放系统升级到UE5之后的代码报错问题解决

关键词&#xff1a; UE4 回放系统 升级 UE5 报错 DemoNetDriver GetDemoCurrentTime GetDemoTotalTime 背景 照着网上教的UE4的回放系统&#xff0c;也叫重播系统&#xff0c;英文Replay。做完了&#xff0c;测试运行正常&#xff0c;可升级到UE5却报了一堆 WorldSetting 和 …

(20230417)最大数合并区间重新排列单词间的空格 按奇偶排序数组 II 数组形式的整数加法

最大数&#xff08;回顾等级&#xff1a;值得&#xff0c;已达最优解&#xff09; 来源&#xff1a;自己LeetCode刷题 usa long cmp(const void* e1, const void* e2) {int* p1(int*)e1;int* p2(int*)e2;long n110;long n210;while(*p1>n1){n1*10;}while(*p2>n2){n2*1…

利用AOP实现统一功能处理

目录 一、实现用户登录校验 实现自定义拦截器 将自定义的拦截器添加到框架的配置中&#xff0c;并且设置拦截的规则 二、实现统一异常处理 三、实现统一数据格式封装 一、实现用户登录校验 在之前的项目中&#xff0c;在需要验证用户登录的部分&#xff0c;每次都需要利…