美文网首页
Flutter 组件之 ListView、GridView

Flutter 组件之 ListView、GridView

作者: Abner_XuanYuan | 来源:发表于2023-10-10 16:26 被阅读0次

1、ListView

列表分类:垂直列表、垂直图文列表、水平列表、动态列表。

1、列表常用参数
ListView({
  Key key,
  //Axis类型可选命名参数,设置沿横轴还是纵轴滚动
  Axis scrollDirection = Axis.vertical,
  //bool类型可选命名参数,用于设置视图的滚动方向是否为读取方向
  bool reverse = false,
  //ScrollController类型可选命名参数,控制滚动视图滚动位置的控制器
  ScrollController controller,
  //bool类型可选命名参数,是否是与父PrimaryScrollController相关联的主滚动视图
  bool primary,
  //ScrollPhysics类型可选命名参数,滚动视图应如何响应用户输入
  ScrollPhysics physics,
  //boo类型可选命名参数,crollDirection中滚动视图的范围是否应由正在查看的内容确定
  bool shrinkWrap = false,
  //EdgeInsetsGeometry类型可选命名参数,内边距,使用EdgeInsets
  EdgeInsetsGeometry padding,
  //double类型可选命名参数,不为空则强制子级在滚动方向上具有给定范围
  this.itemExtent,
  //bool类型可选命名参数,是否将每个子Widget都包装在AutomaticKeepAlive组件中
  bool addAutomaticKeepAlives = true,
  //bool类型可选命名参数,是否将每个子Widget都包装在RepaintBoundary组件中
  bool addRepaintBoundaries = true,
  //bool类型可选命名参数,是否将每个子Widget都包装在IndexedSemantics组件中
  bool addSemanticIndexes = true,
  //double类型可选命名参数,用于设置不可见的缓存区域的大小
  double cacheExtent,
  //List<Widget>类型可选命名参数,用于设置滚动列表的每一项Widget
  List<Widget> children = const <Widget>[],
  //int类型可选命名参数,为ListView中的子列表中Widget提供语义信息的数量
  int semanticChildCount,
  //DragStartBehavior类型可选命名参数,确定处理拖动开始行为的方式
  DragStartBehavior dragStartBehavior = DragStartBehavior.start,
})
//此构造方法采用 IndexedWidgetBuilder,可以根据需要创建子 Widget。适用于有大量或无限个子Widget的ListView。其只对可见的子 Widget 进行构建  
ListView.builder({
  Key key,
  //IndexedWidgetBuilder类型必传参数,为给定索引创建Widget
  @required IndexedWidgetBuilder itemBuilder,
  //int类型可选命名参数,创建Widget的个数
  int itemCount,
  //...省略与ListView相同部分
})
//此构造方法采用 IndexedWidgetBuilder,一个是 itemBuilder,可以根据需要创建子 Widget,另一个是 separatorBuilder,同样构建出现在子项目之间的分隔子项目。此构造函数适用于具有固定数目的子元素的列表视图
ListView.separated({
  Key key,
  //IndexedWidgetBuilder类型必传参数,为给定索引创建Widget
  @required IndexedWidgetBuilder itemBuilder,
  //IndexedWidgetBuilder类型必传参数,为给定索引创建Widget分割Widget
  @required IndexedWidgetBuilder separatorBuilder,
  //int类型必传参数,创建Widget的个数
  @required int itemCount,
  //...省略与ListView相同部分
})
//此构造方法采用 SliverChildDelegate,它提供了自定义模型的其他方面的功能。例如,SliverChildDelegate 可以控制用于估计实际不可见的子代大小的算法  
const ListView.custom({
  Key key,
  //SliverChildDelegate类型必传参数,为ListView提供子Widget的委托
  @required this.childrenDelegate,
    //...省略与ListView相同部分
})
2、示例

垂直列表

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return ListView(
      children: const [
        ListTile(
          title: Text("第一行"),
          subtitle: Text("第一行副标题"),
          titleTextStyle: TextStyle(
            color: Colors.red,
            backgroundColor: Colors.blue,
            fontSize: 30,
          ),
          subtitleTextStyle: TextStyle(
            color: Colors.green,
            backgroundColor: Colors.orange,
            fontSize: 10,
          ),
        ),
        ListTile(
          title: Text("第二行"),
          subtitle: Text("第二行副标题"),
          titleTextStyle: TextStyle(
            color: Colors.red,
            backgroundColor: Colors.blue,
            fontSize: 30,
          ),
          subtitleTextStyle: TextStyle(
            color: Colors.green,
            backgroundColor: Colors.orange,
            fontSize: 10,
          ),
        ),
      ],
    );
  }
}
class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return ListView(
      children: const [
        ListTile(
          leading: Icon(
            Icons.assignment,
            color: Colors.red,
            // size: 40,
          ),
          title: Text("全部订单"),
        ),
        Divider(),
        ListTile(
          leading: Icon(
            Icons.payment,
            color: Colors.green,
            // size: 40,
          ),
          title: Text("待付款"),
        ),
        Divider(),
        ListTile(
          leading: Icon(
            Icons.local_car_wash,
            color: Colors.orange,
            // size: 40,
          ),
          title: Text("待收货"),
        ),
        Divider(),
        ListTile(
          leading: Icon(
            Icons.favorite,
            color: Colors.lightGreen,
            // size: 40,
          ),
          title: Text("我的收藏"),
        ),
        Divider(),
        ListTile(
          leading: Icon(
            Icons.people,
            color: Colors.black54,
            // size: 40,
          ),
          title: Text("在线客服"),
        ),
        Divider(),
      ],
    );
  }
}

垂直图文列表

class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) {
    return ListView(
      children: [
        ListTile(
          leading: Image.network("https://www.itying.com/images/flutter/1.png"),
          title: const Text("华北黄淮高温雨今起强势登场"),
          subtitle: const Text("中国天气网讯 21日开始,华北黄淮高温雨今起强势登场"),
        ),
        const Divider(),
        ListTile(
          trailing: Image.network("https://www.itying.com/images/flutter/1.png"),
          title: const Text("华北黄淮高温雨今起强势登场"),
          subtitle: const Text("中国天气网讯 21日开始,华北黄淮高温雨今起强势登场"),
        ),
        const Divider(),
        ListTile(
          leading: Image.network("https://www.itying.com/images/flutter/1.png"),
          title: const Text("华北黄淮高温雨今起强势登场"),
          // subtitle: const Text("中国天气网讯 21日开始,华北黄淮高温雨今起强势登场"),
        ),
        const Divider(),
      ],
    );
  }
}
class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return ListView(
      padding: const EdgeInsets.all(10),
      children: [
        Image.network("https://www.itying.com/images/flutter/1.png"),
        Container(
          height: 44,
          padding: const EdgeInsets.fromLTRB(0, 10, 0, 10),
          child: const Text(
            "第一行",
            textAlign: TextAlign.center,
            style: TextStyle(fontSize: 18),
          ),
        ),
        const Divider(),
        Image.network("https://www.itying.com/images/flutter/2.png"),
        Container(
          height: 44,
          padding: const EdgeInsets.fromLTRB(0, 10, 0, 10),
          child: const Text(
            "第二行",
            textAlign: TextAlign.center,
            style: TextStyle(fontSize: 18),
          ),
        ),
        const Divider(),
      ],
    );
  }
}

水平列表

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      height: 180,
      child: ListView(
        scrollDirection: Axis.horizontal,
        children: [
          ClipOval(
            //圆角
            child: Container(
              width: 180,
              color: Colors.red,
            ),
          ),
          Container(
              width: 180,
              color: Colors.green,
              child: ClipRRect(
                borderRadius: BorderRadius.circular(50),
                child: Column(
                  children: [
                    Image.network(
                        "https://www.itying.com/images/flutter/1.png"),
                    const Text("第一个文本"),
                  ],
                ),
              )),
          Container(
            color: Colors.orange,
            width: 180,
          ),
        ],
      ),
    );
  }
}

动态列表

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  List<Widget> _initListView() {
    List<Widget> list = [];
    for (var i = 0; i < 10; i++) {
      list.add(const ListTile(
        title: Text("列表"),
      ));
    }
    return list;
  }

  @override
  Widget build(BuildContext context) {
    return ListView(
      children: _initListView(),
    );
  }
}

builder 实现动态列表

class MyApp extends StatelessWidget {
  List<String> list = [];
  MyApp({super.key}) {
    for (var i = 0; i < 10; i++) {
      list.add("列表 -- $i");
    }
  }

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      itemCount: list.length,//数量
      itemBuilder: (BuildContext context, int index) {
        return ListTile(
          title: Text(list[index]),
        );
      },
    );
  }
}

builder 实现动态列表 -- 获取 json 数据

// listData 中测试数据,使用时需要导入头文件
List listData=[
      {
          "title": 'Candy Shop',
          "author": 'Mohamed Chahin',
          "imageUrl": 'https://www.itying.com/images/flutter/1.png',
      },
       {
          "title": 'Childhood in a picture',
          "author": 'Google',
          "imageUrl": 'https://www.itying.com/images/flutter/2.png',
      },
      {
          "title": 'Alibaba Shop',
          "author": 'Alibaba',
          "imageUrl": 'https://www.itying.com/images/flutter/3.png',
      },
      {
          "title": 'Candy Shop',
          "author": 'Mohamed Chahin',
          "imageUrl": 'https://www.itying.com/images/flutter/4.png',
      },
       {
          "title": 'Tornado',
          "author": 'Mohamed Chahin',
          "imageUrl": 'https://www.itying.com/images/flutter/5.png',
      },
      {
          "title": 'Undo',
          "author": 'Mohamed Chahin',
          "imageUrl": 'https://www.itying.com/images/flutter/6.png',
      },
      {
          "title": 'white-dragon',
          "author": 'Mohamed Chahin',
          "imageUrl": 'https://www.itying.com/images/flutter/7.png',
      }      

];
class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      itemCount: listData.length,
      itemBuilder: (BuildContext context, int index) {
        return ListTile(
          leading: Image.network(listData[index]["imageUrl"]),
          title: Text(listData[index]["title"]),
          subtitle: Text(listData[index]["author"]),
        );
      },
    );
  }
}

2、GridView

GridView 网格布局,让可以滚动的元素使用矩阵方式排列(类似 OC 的 UICollectionView)。

1、GridView 创建网格方式

1、GridView.count 方式
2、GridView.extent 方式
3、GridView.builder 方式

2、GridView 常见属性
GridView GridView({
  Key? key,
  Axis scrollDirection = Axis.vertical,  //滚动方向
  //bool类型可选命名参数,用于设置视图的滚动方向是否为读取方向
  bool reverse = false,
  //ScrollController类型可选命名参数,控制滚动视图滚动位置的控制器
  ScrollController? controller,
  //bool类型可选命名参数,是否是与父PrimaryScrollController相关联的主滚动视图
  bool? primary,
  //ScrollPhysics类型可选命名参数,滚动视图应如何响应用户输入
  ScrollPhysics? physics,
  //boo类型可选命名参数,crollDirection中滚动视图的范围是否应由正在查看的内容确定
  bool shrinkWrap = false,
  EdgeInsetsGeometry? padding,  //内边距
  //控制布局,主要用在 GridView.builder 里面
  required SliverGridDelegate gridDelegate,
  //bool类型可选命名参数,是否将每个子Widget都包装在AutomaticKeepAlive组件中
  bool addAutomaticKeepAlives = true,
  //bool类型可选命名参数,是否将每个子Widget都包装在RepaintBoundary组件中
  bool addRepaintBoundaries = true,
  //bool类型可选命名参数,是否将每个子Widget都包装在IndexedSemantics组件中
  bool addSemanticIndexes = true,
  //double类型可选命名参数,用于设置不可见的缓存区域的大小
  double? cacheExtent,
  //List<Widget>类型可选命名参数,用于设置滚动列表的每一项Widget
  List<Widget> children = const <Widget>[],
  //int类型可选命名参数,为ListView中的子列表中Widget提供语义信息的数量
  int? semanticChildCount,
  //DragStartBehavior类型可选命名参数,确定处理拖动开始行为的方式
  DragStartBehavior dragStartBehavior = DragStartBehavior.start,
  //Clip类型可选命名参数,内容将被裁剪(或不裁剪)
  Clip clipBehavior = Clip.hardEdge,
  ScrollViewKeyboardDismissBehavior keyboardDismissBehavior = ScrollViewKeyboardDismissBehavior.manual,
  //保持滑动的偏移量
  String? restorationId,
})
3、网格布局

GridView.count 实现网格布局
GridView.count 构造函数内部使用了 SliverGridDelegateWithFixedCrossAxisCount,我们通过它可以快速的创建横轴固定数量子元素的 GridView。

//示例一
class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return GridView.count(
      crossAxisSpacing: 3,  //widget 左右间的距离
      mainAxisSpacing: 2,  //widget 上下间的距离
      crossAxisCount: 4, //每行列数
      children: const <Widget>[
        Icon(Icons.home),
        Icon(Icons.ac_unit),
        Icon(Icons.search),
        Icon(Icons.settings),
        Icon(Icons.airport_shuttle),
        Icon(Icons.all_inclusive),
        Icon(Icons.beach_access),
        Icon(Icons.cake),
        Icon(Icons.circle),
      ],
    );
  }
}
示例二
///GridView.count 实现网格布局
class MyApp1 extends StatelessWidget {
  const MyApp1({super.key});

  List<Widget> _customList() {
    List<Widget> list = [];
    for (var i = 0; i < 50; i++) {
      list.add(
        Container(
          color: Colors.red,
          alignment: Alignment.center,
          child: Text(
            "第 $i 个元素",
            style: const TextStyle(color: Colors.white, fontSize: 15),
          ),
        ),
      );
    }
    return list;
  }

  @override
  Widget build(BuildContext context) {
    return GridView.count(
      padding: const EdgeInsets.all(10),
      crossAxisSpacing: 3, //水平子 Widget 之间间距
      mainAxisSpacing: 2, //垂直子 Widget 之间间距
      crossAxisCount: 4, //每行列数
      childAspectRatio: 0.8, //宽高比
      children: _customList(),
    );
  }
}

GridView.count 实现动态列表

///GridView.count 实现动态列表
class MyApp extends StatelessWidget {
  const MyApp({super.key});

  List<Widget> _customList() {
    var list = listData.map((value) {
      return Container(
        decoration: BoxDecoration(
            border: Border.all(
          color: const Color.fromRGBO(233, 233, 233, 0.9),
          width: 1,
        )),
        child: Column(
          children: [
            Image.network(value["imageUrl"]),
            const SizedBox(
              height: 12,
            ),
            Text(
              value["title"],
              textAlign: TextAlign.center,
              style: const TextStyle(fontSize: 10),
            ),
          ],
        ),
      );
    });
    return list.toList();
  }

  @override
  Widget build(BuildContext context) {
    return GridView.count(
      crossAxisSpacing: 10,
      mainAxisSpacing: 10,
      crossAxisCount: 2,
      padding: const EdgeInsets.all(10),
      children: _customList(),
    );
  }
}

GridView.extent 实现网格布局
GridView.extent 构造函数内部使用了 SliverGridDelegateWithMaxCrossAxisExtent,我们通过它可以快速的创建横轴子元素为固定最大长度的的 GridView。

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return GridView.extent(
      maxCrossAxisExtent: 100, //横轴子元素的最大长度
      children: const <Widget>[
        Icon(Icons.home),
        Icon(Icons.ac_unit),
        Icon(Icons.search),
        Icon(Icons.settings),
        Icon(Icons.airport_shuttle),
        Icon(Icons.all_inclusive),
        Icon(Icons.beach_access),
        Icon(Icons.cake),
        Icon(Icons.circle),
      ],
    );
  }
}

GridView.builder 实现动态列表


///GridView.builder 实现动态列表
class MyApp extends StatelessWidget {
  const MyApp({super.key});

  //初始化数据
  Widget _customWidget(BuildContext context, int index) {
    return Container(
      decoration: BoxDecoration(
        border: Border.all(color: const Color.fromRGBO(233, 233, 233, 0.9)),
      ),
      child: Column(
        children: [
          Image.network(listData[index]["imageUrl"]),
          const SizedBox(
            height: 12,
          ),
          Text(
            listData[index]["title"],
            textAlign: TextAlign.center,
            style: const TextStyle(fontSize: 15),
          )
        ],
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return GridView.builder(
      gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(//注意此行
        crossAxisCount: 2, //每行 widget 数量
        crossAxisSpacing: 10, //widget 水平之间的距离
        mainAxisSpacing: 10, //widget 垂直之间的距离
      ),
      itemCount: listData.length,
      itemBuilder: _customWidget,
    );
  }
}
class MyApp extends StatelessWidget {
  const MyApp({super.key});

  Widget _customWidget(BuildContext context, int index) {
    return Container(
      decoration: BoxDecoration(
          border: Border.all(
        color: const Color.fromRGBO(233, 233, 233, 0.9),
        width: 1,
      )),
      child: Column(
        children: [
          Image.network(listData[index]["imageUrl"]),
          const SizedBox(
            height: 12,
          ),
          Text(
            listData[index]["title"],
            textAlign: TextAlign.center,
            style: const TextStyle(
              fontSize: 15,
            ),
          )
        ],
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return GridView.builder(
      gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(//注意此行
        maxCrossAxisExtent: 300, //横轴元素的最大长度
        crossAxisSpacing: 10, //widget 水平之间的距离
        mainAxisSpacing: 10, //widget 垂直之间的距离
      ),
      itemCount: listData.length,
      itemBuilder: _customWidget,
    );
  }
}

相关文章

网友评论

      本文标题:Flutter 组件之 ListView、GridView

      本文链接:https://www.haomeiwen.com/subject/tkjnudtx.html