Flutter开发之ListView组件(21)

欢迎点赞+关注。你的鼓励是我写作的动力!

ListView是一个类似列的widget,它的内容对于其渲染框太长时会自动提供滚动。

ListView 摘要:

  • 用于组织盒子中列表的特殊Column
  • 可以水平或垂直放置
  • 检测它的内容超过显示框时提供滚动
  • 比Column配置少,但更易于使用并支持滚动

构建[ListView]有四个选项:

1、ListView(children: [])

适用于构建少量子级的滚动列表,默认滚动方法垂直的
scrollDirection: Axis.vertical

示例:用ListView实现一个banner功能
myBannerView()中实现水平滚动:scrollDirection: Axis.horizontal

import 'package:flutter/material.dart';

Widget myBannerView() {
  return ListView(
    scrollDirection: Axis.horizontal,
    children: [
      Container(
        width: 360,
        height: 200,
        color: Colors.amber[600],
        child: Center(
          child: Image.asset('images/banner.png',fit: BoxFit.fill,
              width: double.infinity,
              height: double.infinity,
          ),
        ),
      ),

      Container(
        width: 360,
        height: 200,
        color: Colors.amber[600],
        child: Center(
          child: Image.asset('images/banner.png',fit: BoxFit.fill,
            width: double.infinity,
            height: double.infinity,
          ),
        ),
      ),

      Container(
        width: 360,
        height: 200,
        color: Colors.amber[500],
        child: Center(
          //https://picsum.photos/250?image=9
        child: Image.network('http://oss.suning.com/uedtool/png_bucket/20195/20190522095508918_灵栖ppt首页5.png',
          fit: BoxFit.fill,
          width: double.infinity,
          height: double.infinity,
        ),
        ),
      ),

      Container(
        width: 360,
        height: 200,
        color: Colors.amber[100],
        child: const Center(child: Text('Entry C')),
      ),
    ],
  );
}


class ScrollListView extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // Use the Todo to create our UI
    return new Scaffold(
      appBar: new AppBar(
        title: new Text("scroll banner"),
      ),
      body: Padding(
        padding: EdgeInsets.all(16),
        child: Column(
          children: [
            Container(
                width: 360,
                height: 200,
                color: Colors.red,
                child: myBannerView(),
            ),
          ],
        ),
      ),
    );
  }
}

上面涉及一个问题:图片如何充满父布局

即使Image.asset中设置了fit: BoxFit.cover,还是不满屏
最终需要在Image.asset增加
width: double.infinity,
height: double.infinity
这两个属性才可以满屏显示。

上面是一种图片充满父布局的方法,还有其他的方法不再陈述。

2、[ListView.builder]

ListView.builder利用IndexedWidgetBuilder来按需构造。这个构造函数适合于具有大量(或无限)子视图的列表视图,因为构建器只对那些实际可见的子视图调用。

ListTile 是快捷cell 的Widget

// 函数2
Widget myListView2(BuildContext context){

  return ListView.builder(
    itemCount: 20,
    itemBuilder: (context, index) {
      return new ListTile(
        title: new Text("我是主标题"),
        subtitle:new Text("我是副标题") ,
        // When a user taps on the ListTile, navigate to the DetailScreen.
        // Notice that we're not only creating a new DetailScreen, we're
        // also passing the current todo through to it!
        onTap: () {
          Navigator.push(
            context,
            new MaterialPageRoute(
              builder: (context) => new DetailScreen(todo: todos[index]),
            ),
          );
        },
      );
    },
  );
}

// 调用的地方
body: myListView2(context),

Flutter开发之ListView组件(21)_第1张图片

3、[ListView.separated]

有直接的分隔符设置方式,对分隔符列表应用更实用;设置 separatorBuilder 属性即可;相当于iOS 的区头、区尾。

下面是一个类中的全部代码

// 数据源
final List titleItems = [
  '自定义cell',
  'GridView',
  'Stack Test',
  'pages',
  'zoom_out_map',
  'zoom_out',
  'youtube_searched_for',
  'wifi_tethering',
  'wifi_lock',
  'widgets',
  'weekend',
  'web',
  '图accessible',
  'ac_unit',
];

final List iconItems = [
  new Icon(Icons.keyboard, size: 50),
  new Icon(Icons.print, size: 50),
  new Icon(Icons.router, size: 50),
  new Icon(Icons.pages, size: 50),
  new Icon(Icons.zoom_out_map, size: 50),
  new Icon(Icons.zoom_out, size: 50),
  new Icon(Icons.youtube_searched_for, size: 50),
  new Icon(Icons.wifi_tethering, size: 50),
  new Icon(Icons.wifi_lock, size: 50),
  new Icon(Icons.widgets, size: 50),
  new Icon(Icons.weekend, size: 50),
  new Icon(Icons.web, size: 50),
  new Icon(Icons.accessible, size: 50),
  new Icon(Icons.ac_unit, size: 50),
];

final List subTitleItems = [
  'subTitle: CustomCell',
  'subTitle: GardViewTest',
  'subTitle: StackTest',
  'subTitle: pages',
  'subTitle: zoom_out_map',
  'subTitle: zoom_out',
  'subTitle: youtube_searched_for',
  'subTitle: wifi_tethering',
  'subTitle: wifi_lock',
  'subTitle: widgets',
  'subTitle: weekend',
  'subTitle: web',
  'subTitle: accessible',
  'subTitle: ac_unit',
];

class DemoList extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('DemoList'),
      ),
      body: new ListView.separated(
        itemCount: 20,
        itemBuilder: (context, index) {
          return new ListTile(
              contentPadding: EdgeInsets.fromLTRB(10, 0, -5, 20),
              leading: iconItems[index % 10],
              title: Container(
                padding: EdgeInsets.fromLTRB(10, 5, 0, 30),
                child: new Text(
                  titleItems[index % 10],
                  style: TextStyle(fontSize: 18),
                ),
              ),
              subtitle: new Text(subTitleItems[index % 10]),
              trailing: new Icon(
                Icons.keyboard_arrow_right,
                size: 40,
                color: Colors.black,
              ),
              onTap: () {
                routeSubpage(context, index);
              });
        },

        //和itemBuilder 同级别的执行
        separatorBuilder: (BuildContext context, int index) {
          if (index == 2) {
            return new Container(
              height: 40.0,
              color: Colors.red,
              child: new Center(
                child: new Text("类型1"),
              ),
            );
          } else if (index == 7) {
            return new Container(
              height: 40.0,
              color: Colors.blue,
              child: new Center(
                child: new Text("类型2"),
              ),
            );
          } else if (index == 14) {
            return new Container(
              height: 40.0,
              color: Colors.yellow,
              child: new Center(
                child: new Text("类型3"),
              ),
            );
          } else {
            return Divider(
              color: Colors.red,
              height: 2,
              indent: 20,
            );
          }
        },
      ),
    );
  }
}

// onTap自定义跳转页面
void routeSubpage(BuildContext context, int index) {
  print("点击了第几个cell----$index");
}

4、[ListView.custom]

我的理解是自定义的cell。

// ignore: slash_for_doc_comments
/**
 * 继承SliverChildBuilderDelegate  可以对列表的监听
 */
class MyChildrenDelegate extends SliverChildBuilderDelegate {
  MyChildrenDelegate(
      Widget Function(BuildContext, int) builder, {
        int childCount,
        bool addAutomaticKeepAlive = true,
        bool addRepaintBoundaries = true,
      }) : super(builder,
      childCount: childCount,
      addAutomaticKeepAlives: addAutomaticKeepAlive,
      addRepaintBoundaries: addRepaintBoundaries);

  ///监听 在可见的列表中 显示的第一个位置和最后一个位置
  @override
  void didFinishLayout(int firstIndex, int lastIndex) {
    print('firstIndex: $firstIndex, lastIndex: $lastIndex');
  }

  ///可不重写 重写不能为null  默认是true  添加进来的实例与之前的实例是否相同 相同返回true 反之false
  ///listView 暂时没有看到应用场景 源码中使用在 SliverFillViewport 中
  @override
  bool shouldRebuild(SliverChildBuilderDelegate oldDelegate) {
    // TODO: implement shouldRebuild
    print("oldDelegate$oldDelegate");
    return super.shouldRebuild(oldDelegate);
  }
}
// 以上部分为重写内容

//listView custom 构建
//
// 函数声明
_onClick(){
  print("你好啊,小驹!");
}

Widget listViewLayoutCustom() {
//    return ListView.custom(childrenDelegate: new MyChildrenDelegate());
  return ListView.custom(
    //确定每一个item的高度 会让item加载更加高效
    itemExtent: 60.0,
    scrollDirection: Axis.vertical,
    // padding: EdgeInsets.only(top:20),
    padding: EdgeInsets.all(20),
    childrenDelegate: MyChildrenDelegate(
          (BuildContext context, int index) {
        return  new GestureDetector(
          onTap:(){
            print("你好啊,小驹!");
            routeSubpage(context, index);
          },
          child: Container(
            decoration: BoxDecoration(
              color: Colors.blue,
            ),

            child: Column(
              mainAxisAlignment: MainAxisAlignment.start,
              children: [

                //1. cell content
                Container(
                  padding: EdgeInsets.only(left: 10),
                  height: 58,
                  child: new Row(
                    // start 左对齐 spaceEvenly 平分
                    mainAxisAlignment: MainAxisAlignment.start,
                    children: [

                      Text(
                        "你好你好",
                        style: new TextStyle(
                            fontSize: 18.0, color: Colors.red,
                            decoration: TextDecoration.underline,       // 划线位置
                            decorationStyle: TextDecorationStyle.solid // 划线样式
                        ),
                      ),

                      Text(
                        "你好你好111",
                        style: new TextStyle(fontSize: 18.0, color: Colors.orange),
                      ),

                      Container(
                        padding: EdgeInsets.only(top: 0),
                        width: 90,
                        child: Text(
                          "你好你好2226",
                          textAlign: TextAlign.left, // 对齐方式

                          // 不指定宽度时,下面没有效果,尾部显示 黄色相间的胶带色块
                          overflow: TextOverflow.ellipsis,// 文字显示不全样式
                          maxLines: 1, // 最大显示行数,默认为最大
                          style: TextStyle(fontSize: 18.0, color: Colors.black54),
                        ),
                      ),

                    ],
                  ),
                ),

                //2. 分割线
                Container(
                  height: 2,
                  child:Divider(height:2.0,indent:15.0,color: Colors.red,),
                ),

              ],

            ),
          ),
        );
      },
      childCount: 20,
    ),
    cacheExtent: 0.0,
  );
}

class CustomCell extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('自定义cell'),
      ),

      body: listViewLayoutCustom(),
    );
  }
}

void routeSubpage(BuildContext context, int index) {
  print("点击了第几个cell----$index");
}

这里面的代码涉及自定义视图,文本的显示,布局等。读者可以细细品味。

总结

关于Flutter ListView的用法基本都在这里了,要想用好ListView,还要加大练习,在实践中琢磨ListView的使用场景和使用技巧。

欢迎点赞+关注。你的鼓励是我写作的动力!



Flutter ListView详解 - trues的博客 写的不错
https://blog.csdn.net/hao_m582/article/details/84112278

你可能感兴趣的:(Flutter开发教程,ListView组件,Flutter,ListView组件,Flutter,ListView,ListView组件的用法,ListView自定义cell)