flutter 实现列表的几种方法,ListView简单实现列表的下拉刷新、动态生成

1,647 阅读3分钟

flutter 实现列表(ListView)的几种方法,简单实现列表的下拉刷新、动态生成

 列表在软件上是一个最常用的部分,几乎所有软件APP都离不开列表,比如聊天软件有好友列表,购物软件有商品列表,音乐播放软件有音乐列表,所以具备列表实现的知识很有必要。在flutter中列表相关的组件有很多,我们现在就用ListView来实现一个列表吧。

ListView

 ListView是最常用的可滚动组件之一,它可以沿一个方向线性排布所有子组件,并且它也支持列表项懒加载(在需要时才会创建)。下边是ListView的默认构造函数。默认构造函数有一个children参数,它接受一个Widget列表(List)。这种方式适合只有少量的子组件数量已知且比较少的情况,反之则应该使用ListView.builder 按需动态构建列表项。

ListView({
  ...  
  //可滚动widget公共参数
  Axis scrollDirection = Axis.vertical,
  bool reverse = false,
  ScrollController? controller,
  bool? primary,
  ScrollPhysics? physics,
  EdgeInsetsGeometry? padding,
  
  //ListView各个构造函数的共同参数  
  double? itemExtent,
  Widget? prototypeItem, //列表项原型,后面解释
  bool shrinkWrap = false,
  bool addAutomaticKeepAlives = true,
  bool addRepaintBoundaries = true,
  double? cacheExtent, // 预渲染区域长度
    
  //子widget列表
  List<Widget> children = const <Widget>[],
})

ListView.builder

 ListView.builder适合列表项比较多或者列表项不确定的情况。下边是结合ListTile生成10个列表的例子。ListView.builder 接受两个参数:itemCount: int,itemBuilder: @required IndexedWidgetBuilder itemBuilder, itemCount 这个参数声明了 list 的长度,这个值表明 ListView 中会存在多少个 item 子项。从 itemBuilder 的表面含以上也能够知道它是用来构造每个子项组件的,它的类型是IndexedWidgetBuilder,其实是一个方法,接受 context 和 index 两个参数。context:构造的上下文,index: 当前索引。

class List extends StatelessWidget {
  const List({super.key});
  @override
  Widget build(BuildContext context) {
    return ListView.builder(
        itemCount: 20,
        itemExtent: 50.0, //强制高度为50.0
        itemBuilder: (BuildContext context, int index) {
          return ListTile(title: Text("$index"));
        });
  }
}

1.png

ListTile

 ListTile 通常用于在 Flutter 中填充 ListView,我们可以对ListTile设置来美化上边实现的列表,可以通过subtitle添加副标题,通过leading设置头像图标,通过trailing设置尾部图标,selected为选中状态,默认为 false。

class List extends StatefulWidget {
  const List({super.key});

  @override
  State<List> createState() => _ListState();
}

class _ListState extends State<List> {
  // bool selectedtrue=false;
  @override
  Widget build(BuildContext context) {
    return ListView.builder(
        itemCount: 20,
        itemExtent: 60.0, //强制高度为50.0
        itemBuilder: (BuildContext context, int index) {
          return ListTile(
            leading: const Icon(Icons.people, color: Colors.blue),
            title: Text(
              "$index  列表标题",
              style: TextStyle(color: Colors.blue),
            ),
            //subtitle:Text("$index 列表副标题") ,
            trailing: const Icon(
              Icons.keyboard_arrow_right,
              color: Colors.blue,
            ),
            //selected: selectedtrue,
            hoverColor: Colors.blue,
            focusColor: Colors.blue,
            // tileColor: Colors.yellow,
            autofocus: true,
            onTap: () {
              print("$index");
              setState(() {
                //selectedtrue=true;
              });
            },
          );
        });
  }
}

2.png

ListView.separated 带分隔符的列表

 当我们想要列表有分割线的时候可以用ListView.separated, ListView.separated与 ListView.builder 的唯一不同就是多了个separatorBuilder,通过接受 BuildContext context, int index 两个参数,再返回一个 Widget,其他的和 ListView.builder 的使用方法一样。separatorBuilder 也可以使用别的 Widget当做分隔符,图片、图标都可以:

class List extends StatefulWidget {
  const List({super.key});
  @override
  State<List> createState() => _ListState();
}

class _ListState extends State<List> {
  // bool selectedtrue=false;
  @override
  Widget build(BuildContext context) {
    return ListView.separated(
        itemCount: 20,
        // itemExtent: 60.0, //强制高度为50.0
        separatorBuilder: (BuildContext context, int index) {
          return const Divider(
            color: Colors.red,
          );
        },
        itemBuilder: (BuildContext context, int index) {
          return ListTile(
            leading: const Icon(Icons.people, color: Colors.blue),
            title: Text(
              "$index  列表标题",
              style: TextStyle(color: Colors.blue),
            ),
            //subtitle:Text("$index 列表副标题") ,
            trailing: const Icon(
              Icons.keyboard_arrow_right,
              color: Colors.blue,
            ),
            //selected: selectedtrue,
            hoverColor: Colors.blue,
            focusColor: Colors.blue,
            // tileColor: Colors.yellow,
            autofocus: true,
            onTap: () {
              print("$index");
              setState(() {
                //selectedtrue=true;
              });
            },
          );
        });
  }
}

3.png

动态生成长列表

 一般情况下,我们需要根据数据来生成列表,现在就模仿实现一下。首先哦们创建一个列表来存放我们的源数据,命名为listData,在listData放入标题、图标、颜色,这样我们可以生成不同图标、不同标题、不同颜色的列表。如果有其他需求,比如定制副标题等需求,修改listData里面的元素就可以了。列表使用ListView.separated生成,有分隔符看起来清楚一点,当然分隔元素也可以换成其他的组件。

class Listbuildtest extends StatefulWidget {
  const Listbuildtest({super.key});
  @override
  State<Listbuildtest> createState() => _ListbuildtestState();
}

class _ListbuildtestState extends State<Listbuildtest> {
  // bool selectedtrue=false;
  void funcfor() {
    print("ndex");
  }

  /* @override
  void initState() {//重写初始化函数
    for (var i = 0; i < 10; i++) {
      //sleep(const Duration(seconds: 5));
      print(i.toString());
      print("initState*************");
      super.initState();
    }
  }*/
  List listData = [//数据列表
    {
      'title': 'Python 创作季,秀出你的文章',
      'icon': Icons.people,
      'color': Colors.blue,
    },
    {
      'title': 'Golang 创作季,秀出你的文章',
      'icon': Icons.gamepad_rounded,
      'color': Colors.orange,
    },
    {
      'title': 'Dart 创作季,秀出你的文章',
      'icon': Icons.network_cell,
      'color': Colors.green,
    },
    {
      'title': 'C/C++ 创作季,秀出你的文章',
      'icon': Icons.cabin,
      'color': Colors.pink,
    },
    {
      'title': 'java 创作季,秀出你的文章',
      'icon': Icons.access_alarm_rounded,
      'color': Colors.purple,
    }
  ];
  @override
  Widget build(BuildContext context) {
    return ListView.separated(
        itemCount: listData.length,
        // itemExtent: 60.0, //强制高度为50.0
        separatorBuilder: (BuildContext context, int index) {
          return const Divider(
            color: Colors.red,
          );
        },
        itemBuilder: buildlist);
  }

  Widget buildlist(BuildContext context, int index) {
    return ListTile(
      leading: Icon(listData[index]['icon'],  color: listData[index]['color'],),
      title: Text(
        listData[index]['title'],
        style:  TextStyle( color: listData[index]['color'],),
      ),
      //subtitle:Text("$index 列表副标题") ,
      trailing:  Icon(
        Icons.keyboard_arrow_right,
        color: listData[index]['color'],
      ),
      //selected: selectedtrue,
      // hoverColor: Colors.blue,
      //focusColor: Colors.blue,
      // tileColor: Colors.yellow,
      autofocus: true,
      onTap: () {
        funcfor();
        print("$index");
        setState(() {
          //selectedtrue=true;
        });
      },
    );
  }
}

4.png

列表下拉刷新

 RefreshIndicator是Material风格的下拉刷新组件,我们直接使用RefreshIndicator嵌套list组件就可以了,每次刷新我们添加一列PHP。RefreshIndicator的child和onRefresh是必须要实现的。在下触发下拉事件后调用setState改变组件状态,实现界面刷新。

class Listbuildtest extends StatefulWidget {
  const Listbuildtest({super.key});
  @override
  State<Listbuildtest> createState() => _ListbuildtestState();
}

class _ListbuildtestState extends State<Listbuildtest> {
  // bool selectedtrue=false;
  void funcfor() {
    print("ndex");
  }

  /* @override
  void initState() {//重写初始化函数
    for (var i = 0; i < 10; i++) {
      //sleep(const Duration(seconds: 5));
      print(i.toString());
      print("initState*************");
      super.initState();
    }
  }*/
  List listData = [
    //数据列表
    {
      'title': 'Python 创作季,秀出你的文章',
      'icon': Icons.people,
      'color': Colors.blue,
    },
    {
      'title': 'Golang 创作季,秀出你的文章',
      'icon': Icons.gamepad_rounded,
      'color': Colors.orange,
    },
    {
      'title': 'Dart 创作季,秀出你的文章',
      'icon': Icons.network_cell,
      'color': Colors.green,
    },
    {
      'title': 'C/C++ 创作季,秀出你的文章',
      'icon': Icons.cabin,
      'color': Colors.pink,
    },
    {
      'title': 'java 创作季,秀出你的文章',
      'icon': Icons.access_alarm_rounded,
      'color': Colors.purple,
    }
  ];
  @override
  Widget build(BuildContext context) {
    return RefreshIndicator(//下拉刷新组件
      onRefresh: () async {
        setState(() {
          print("下拉刷新");
          listData.add(//每次刷新对listdata添加一个元素
            {
              'title': 'PHP 创作季,秀出你的文章',
              'icon': Icons.pages,
              'color': Colors.red,
            },
          );
        });
      },
      child: ListView.separated(
          itemCount: listData.length,
          // itemExtent: 60.0, //强制高度为50.0
          separatorBuilder: (BuildContext context, int index) {
            return const Divider(
              color: Colors.red,
            );
          },
          itemBuilder: buildlist),
    );
  }

  Widget buildlist(BuildContext context, int index) {
    return ListTile(
      leading: Icon(//头部图标
        listData[index]['icon'],
        color: listData[index]['color'],
      ),
      title: Text(//标题
        listData[index]['title'],
        style: TextStyle(
          color: listData[index]['color'],
        ),
      ),
      //subtitle:Text("$index 列表副标题") ,
      trailing: Icon(//尾部图标
        Icons.keyboard_arrow_right,
        color: listData[index]['color'],
      ),
      //selected: selectedtrue,
      // hoverColor: Colors.blue,
      //focusColor: Colors.blue,
      // tileColor: Colors.yellow,
      autofocus: true,//自动聚焦
      onTap: () {//点击事件
        funcfor();
        print("$index");
        setState(() {
          //selectedtrue=true;
        });
      },
    );
  }
}

5.png

总结

 列表的实现就先到这里,实际使用的时候肯定需要更多的知识和技巧,这些远远不够。本来想实现列表数据定时自动更新的,但是奈何查了半天没找到方法,暂时先放弃了吧。