8.老板要我做个新闻界面,我反手一套列表组件~(列表系列)

Posted 阿 T

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了8.老板要我做个新闻界面,我反手一套列表组件~(列表系列)相关的知识,希望对你有一定的参考价值。

在这里插入图片描述

前言

普通的基础组件自然不能满足我们的日常开发需求,所以小T带大家了解Flutter开发中的常用组件

本篇将介绍常用的组件。分为上中下三篇在这里插入图片描述

结构图:

在这里插入图片描述

本小结内容:

1.ListView (详解)

2.GridView

3.PageView (用处超多哦~)

好好看好好学 在这里插入图片描述

ListView:

1.ListView

  1. 普通ListView (适用于列表中含有少量元素的场景)

  2. ListView.builder (适用于子 Widget 较多,且视觉效果呈现某种规律性的场景)

  3. ListView.separated (适用于子 Widget 较多,且视觉效果呈现某种规律性、每个子 Widget 之间需要分割线的场景)

在 Flutter 中,ListView 可以沿一个方向(垂直或水平方向)来排列其所有子 Widget

1.普通ListView
在这里插入图片描述
一个很简单的列表

让我们来看看源码:

ListView({
  Axis scrollDirection = Axis.vertical,
  ScrollController controller,
  ScrollPhysics physics,
  bool shrinkWrap = false,
  EdgeInsetsGeometry padding,
  this.itemExtent,
  double cacheExtent,
  List<Widget> children = const <Widget>[],
})

源码详解:

  • scrollDirection: 列表的滚动方向,可选值有Axishorizontalvertical,可以看到默认是垂直方向上滚动;
  • controller: 控制器,与列表滚动相关,比如监听列表的滚动事件;
  • physics: 列表滚动至边缘后继续拖动的物理效果,androidios效果不同。Android会呈现出一个波纹状(对应ClampingScrollPhysics),而iOS上有一个回弹的弹性效果(对应BouncingScrollPhysics)。如果你想不同的平台上呈现各自的效果可以使用AlwaysScrollableScrollPhysics,它会根据不同平台自动选用各自的物理效果。如果你想禁用在边缘的拖动效果,那可以使用NeverScrollableScrollPhysics
  • shrinkWrap: 该属性将决定列表的长度是否仅包裹其内容的长度。当ListView嵌在一个无限长的容器组件中时,shrinkWrap必须为true,否则Flutter会给出警告;
  • padding: 列表内边距;
  • itemExtent: 子元素长度。当列表中的每一项长度是固定的情况下可以指定该值,有助于提高列表的性能(因为它可以帮助ListView在未实际渲染子元素之前就计算出每一项元素的位置);
  • cacheExtent: 预渲染区域长度,ListView会在其可视区域的两边留一个cacheExtent长度的区域作为预渲染区域(对于ListView.buildListView.separated构造函数创建的列表,不在可视区域和预渲染区域内的子元素不会被创建或会被销毁);
  • children: 容纳子元素的组件数组。

效果图代码:

ListView(
  children: [
    ListTile(
      leading: Icon(
        Icons.home,
        color: Colors.cyan, // 图标颜色
      ),
      title: Text("首页"),
      selected: true, // 设置状态为选中状态
    ),
    ListTile(
      leading: Icon(
        Icons.add_shopping_cart,
        color: Colors.black54,
      ),
      title: Text("购物车"),
    ),
    ListTile(
      leading: Icon(
        Icons.account_circle,
        color: Colors.black54,
      ),
      title: Text("我的"),
    )
  ],
)

可以看到,默认构造函数的用法非常之简单,直接把子元素组件放在children数组中就可以了。但是潜在的问题前面也已经解释过,对于长列表这种应用场景还是应该用ListView.build构造函数性能会更好~

2. ListView.builder

它的源码和ListView相比较就多了

  • itemCount: 列表中元素的数量;
  • itemBuilder: 子元素的渲染方法,允许自定义子元素组件(等同于rnFlatList组件的renderItem属性)。

适合在多数据的列表下使用

让我们来体验它的魅力吧:

先模仿一下真实的Json数据:

LinkedHashMap<String, dynamic> builderTest = {
  "data": {
    "0": {"userId": "1", "userName": "阿T One"},
    "1": {"userId": "2", "userName": "阿T Two"},
    "2": {"userId": "3", "userName": "阿T Three"},
  },
  "code": "200",
  "msg": "success"
} as LinkedHashMap<String, dynamic>;

在这里插入图片描述
实现:

ListView.builder(
    itemCount: builderTest["data"].length, //data数据中的长度
    itemBuilder: (context, int index) {  //index是自增的~
      return Column(
        children: [
          Container(
            margin: EdgeInsets.only(top: 5),
            alignment: Alignment.center,
            child: Text("用户名" +
                builderTest["data"][index.toString()]["userName"]),
          ),
        ],
      );
    })

非常适合开发的日常使用在这里插入图片描述

**3.**ListView.separated

绝大多数列表类的需求我们都可以用ListView.builder构造函数来解决问题,不过有的列表子项之间需要分割线,此时我们可以用Flutter提供的另一个构造函数ListView.separated来创建列表。

就多了个分割线,还是ListView.builder香~

GridView:

常见的GridView:

  1. GridView默认构造函数可以类比于ListView默认构造函数,适用于有限个数子元素的场景,因为GridView组件会一次性全部渲染children中的子元素组件;
  2. GridView.builder构造函数可以类比于ListView.builder构造函数,适用于长列表的场景,因为GridView组件会根据子元素是否出现在屏幕内而动态创建销毁,减少内存消耗,更高效渲染;
  3. GridView.count构造函数是GrdiView使用SliverGridDelegateWithFixedCrossAxisCount的简写(语法糖),效果完全一致;
  4. GridView.extent构造函数式GridView使用SliverGridDelegateWithMaxCrossAxisExtent的简写(语法糖),效果完全一致。

在这里插入图片描述
咱们这个只讲解最常用的:GridView.bulider

和ListView.builder一样,这个组件适用于:

当子widget比较多时,我们可以通过GridView.builder来动态创建子widget

GridView.builder 必须指定的参数有两个:

GridView.builder(
 ...
 @required SliverGridDelegate gridDelegate, 
 @required IndexedWidgetBuilder itemBuilder,
)

其中itemBuilder为子widget构建器

效果图:

在这里插入图片描述
实现:(上面的Json数据不要忘记写哦~)

GridView.builder(
    gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
        crossAxisCount: 3, //每行三列
        childAspectRatio: 1.0 //显示区域宽高相等
        ),
    itemCount: builderTest["data"].length,
    itemBuilder: (context, index) {
      return Column(
        children: [
          Container(
            color: Colors.amberAccent,
            margin: EdgeInsets.only(top: 100,right: 5,left: 5),
            alignment: Alignment.center,
            child: Text("用户名" +
                builderTest["data"][index.toString()]["userName"]),
          ),
        ],
      );
    })

咱也可以自己改进这个组件,造轮子哈哈~
在这里插入图片描述

PageView:

PageView可用于Widget的整屏滑动切换,如当代常用的短视频APP中的上下滑动切换的功能,也可用于横向页面的切换,如APP第一次安装时的引导页面,也可用于开发轮播图功能

例:微信的界面可以左右切换,可以用PageView实现

先让我们看看PageView的源码:

我们来实现一个简单的轮播图:
在这里插入图片描述
可以左右切换~

PageView({
  Key? key,
  this.scrollDirection = Axis.horizontal, //滚动方向
  this.reverse = false, //是否反向,这个反向根阅读习惯有关
  PageController? controller, //控制器 !!
  this.physics, //滚动的物理效果 
  this.pageSnapping = true, //自定义滚动行为时,设置为false,滚动起来就向list一样
  this.onPageChanged, //页面切换回调
  List<Widget> children = const <Widget>[],
  this.dragStartBehavior = DragStartBehavior.start,//影响DragStartDetails返回offset的方式
  this.allowImplicitScrolling = false,//在头部或者尾部继续滚动时,手势事件是否传给上层widget消费
})

代码实现:

第一步:定义需要的参数:

PageController _pageController;
Timer _timer; //骚操作所使用的,不需要可以注释
int _index = 0;
List bannerList = [
  "https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=2675667394,3836121343&fm=26&gp=0.jpg",
  "https://img2.baidu.com/it/u=2228201159,3924578095&fm=26&fmt=auto&gp=0.jpg",
  "https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=2975272371,772428775&fm=26&gp=0.jpg",
  "https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=3644428647,2654791241&fm=26&gp=0.jpg",
];

第二步:初始化:

@override
void initState() {
  super.initState();
  _pageController = PageController(
    initialPage: _index, //默认在第几个
    viewportFraction: 1, // 占屏幕多少,1为占满整个屏幕
    keepPage: true, //是否保存当前 Page 的状态,如果保存,下次回复保存的那个 page,initialPage被忽略,
    //如果为 false 。下次总是从 initialPage 开始。
  );
  // _timer = Timer.periodic(const Duration(seconds: 2), (timer) {
    //   _index++;
    //   _pageController.animateToPage(
    //     _index % 3, //跳转到的位置
    //     duration: Duration(milliseconds: 16), //跳转的间隔时间
    //     curve: Curves.fastOutSlowIn, //跳转动画
    //   );
    // });
}

第三步:主体代码:

return Scaffold(
  appBar: AppBar(
    leading: null,
    automaticallyImplyLeading: false,
    title: Text("title"),
  ),
  body: PageView(
    scrollDirection: Axis.horizontal,
    reverse: false,
    controller: _pageController,
    physics: BouncingScrollPhysics(),
    pageSnapping: true,
    onPageChanged: (index) {
      print('当前是第$index图片');
    },
    children: <Widget>[
      Image.network(
        bannerList[0],
        width: MediaQuery.of(context).size.width,
      ),
      Image.network(
        bannerList[1],
        width: MediaQuery.of(context).size.width,
      ),
      Image.network(
        bannerList[2],
        width: MediaQuery.of(context).size.width,
      ),
      Image.network(
        bannerList[3],
        width: MediaQuery.of(context).size.width,
      )
    ],
  ),
);

第四步:销毁处理

@override
void dispose() {
  _pageController.dispose();
  // _timer.cancel();
  super.dispose();
}

这样就可以啦~

骚操作:让它自己动起来

初始化时加个定时器:

_timer = Timer.periodic(const Duration(seconds: 2), (timer) {
      _index++;
      _pageController.animateToPage(
        _index % 3, //跳转到的位置
        duration: Duration(milliseconds: 16), //跳转的间隔时间
        curve: Curves.fastOutSlowIn, //跳转动画
      );
    });

然后在销毁做进一步处理

_timer.cancel();

这样就是一个自己会动的轮播图啦~

同学们在日常生活中要根据实际情况灵活运用哦~

欢迎留言纠正 ~

我是阿T一个幽默的程序员 我们下期再见~

添加我为你的好友,领取源码以及Flutter学习资料~

在这里插入图片描述

以上是关于8.老板要我做个新闻界面,我反手一套列表组件~(列表系列)的主要内容,如果未能解决你的问题,请参考以下文章

老板要我开发一个简单的工作流引擎

老板要我开发一个简单的工作流引擎

老板要我开发一个简单的工作流,15 次需求变更,我干到秃了。。

老板要我开发一个简单的工作流,15 次需求变更,我干到秃了。。

老板要我开发一个简单的工作流,15 次需求变更,我干到秃了。。

老大要我开发一个简单的工作流引擎