Flutter组件渲染集合的几种方式之详解与实战举例(更新)

一、Wrap组件

Wrap
以下是flutter默认给我们提供的接口

Wrap({
    Key key,
    this.direction = Axis.horizontal,
    this.alignment = WrapAlignment.start,
    this.spacing = 0.0,
    this.runAlignment = WrapAlignment.start,
    this.runSpacing = 0.0,
    this.crossAxisAlignment = WrapCrossAlignment.start,
    this.textDirection,
    this.verticalDirection = VerticalDirection.down,
    List<Widget> children = const <Widget>[],
  }) : super(key: key, children: children);

提供了很多属性,介绍一下属性都是干嘛的

属性作用
direction扩展方式 比如横向堆砌
alignment对齐方式
spacing主轴空隙间距
runAlignment run的对齐方式
runSpacing run空隙间距
crossAxisAlignment纵轴对齐方式
textDirection文本对齐方向
verticalDirection确定垂直放置子元素的顺序,以及如何在垂直方向上解释开始和结束,默认down children 需要放置的组件列表

当选中该金额项目时,触发点击事件和样式,如下用Wrap实现,for循环遍历,拿到当前索引值

在这里插入图片描述

int specIndex;
 Wrap(
          runSpacing: 10,
          spacing: 20,
          children: _buildMoneyItem(),
            ),
  List<Widget> _buildMoneyItem() {
    List<Widget> spectListWidget = [];
    for (int i = 0; i < list.length; i++) {
      spectListWidget.add(GestureDetector(
        onTap: () {
          selectedAccountValueSave = listValue[i];
          setState(() {
            specIndex = i;
          });
        },
        child: Container(
          height: 40,
          width: 75,
          alignment: Alignment.center,
          child: Center(
            child: Text(
              list[i],
              style: TextStyle(fontSize: 16),
            ),
          ),
          // padding: EdgeInsets.only(left: 10, right: 10),
          decoration: BoxDecoration(
              border: Border(
                top: BorderSide(
                    width: 1.0, color: specIndex == i ? colorRed : colorGrey),
                left: BorderSide(
                    width: 1.0, color: specIndex == i ? colorRed : colorGrey),
                right: BorderSide(
                    width: 1.0, color: specIndex == i ? colorRed : colorGrey),
                bottom: BorderSide(
                    width: 1.0, color: specIndex == i ? colorRed : colorGrey),
              ),
              color: Color(0xFFf7f7f7),
              borderRadius: BorderRadius.all(Radius.circular(2))),
        ),
      ));
    }
    return spectListWidget;
  }
二、GridView.count

控件网格的主轴方向是它滚动的方向( scrollDirection)。 最常用的网格布局是GridView.count,它创建了一个在横轴上具有固定数量 网格块 的平铺的布局

GridView源码

GridView({
    Key key,
    Axis scrollDirection = Axis.vertical, 
    bool reverse = false,  
    ScrollController controller,
    bool primary,
    ScrollPhysics physics,
    bool shrinkWrap = false, 
    EdgeInsetsGeometry padding,  
    @required this.gridDelegate, 
    bool addAutomaticKeepAlives = true,
    bool addRepaintBoundaries = true,
    bool addSemanticIndexes = true,
    double cacheExtent,
    List<Widget> children = const <Widget>[],
    int semanticChildCount,
  })

属性值类型说明
scrollDirectionAxis设置滚动的方向,horizontal(水平)或vertical(垂直)
reverse bool是否翻转
controllerScrollController用来控制滚动位置及监听滚动事件
shrinkWrapbool是否根据子widget的总长度来设置GridView的长度
paddingEdgeInsetsGeometry间距
gridDelegateSliverGridDelegate控制子Widget如何进行布局
childrenList子控件

gridDelegate

该属性接收一个SliverGridDelegate类型的值,主要是用来控制子Widget如何进行布局。

在这里插入图片描述
他有如下两个实现类
SliverGridDelegateWithMaxCrossAxisExtent和SliverGridDelegateWithFixedCrossAxisCount
构造方法

 const SliverGridDelegateWithMaxCrossAxisExtent({
    @required this.maxCrossAxisExtent, //子控件的最大宽度,实际宽度是根据交叉轴的值进行平分,也就是说最大宽度并不一定是实际宽度,很有可能子控件的实际宽度要小于设置的最大宽度
    this.mainAxisSpacing = 0.0, //主轴之间的间距
    this.crossAxisSpacing = 0.0,//交叉轴之间的间距
    this.childAspectRatio = 1.0,//子控件的宽高比
  }
GridView(
      scrollDirection: Axis.vertical,
      gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
        maxCrossAxisExtent: 100, //子控件最大宽度为100
        childAspectRatio: 0.5,//宽高比为1:2
        crossAxisSpacing: 10,
        mainAxisSpacing: 10,
      ),
      padding: EdgeInsets.all(10),
      children: List.generate(
        20,
        (index) {
          return Box(index + 1);
        },
      ),
    );

List.generate()

List.generate(images.length, (i){
  return Container(
    margin: EdgeInsets.only(left:20.0),
      child: 
        Image.network("${images[i]}",
          width: 375.0,
          fit: BoxFit.fitWidth,
        ),
   );
}),

实战举例

GridView.count(
        shrinkWrap: true,
        physics: NeverScrollableScrollPhysics(),
        crossAxisSpacing: 20,
        crossAxisCount: 3,
        children: menuList.map((e) {
          return InkWell(
            onTap: () {
              jumpToTargetPage(e.tag);
            },
            child: Column(
              children: [
                Image.asset(
                  e.icon,
                  height: 36,
                  width: 36,
                ),
                SizedBox(height: 10),
                Text(
                  e.title,
                  style: TextStyle(fontSize: 12, color: Colours.textBlack32),
                ),
              ],
            ),
          );
        }).toList(),
      )
  void jumpToTargetPage(String tag) {
    String pageName;
    Map arguments;
    switch (tag) {
      case "1":
        pushNamedPage(PublishRoute, arg: arguments);
        break;
      case "2":
        break;
    }
    if (pageName != null) {
      pushNamedPage(pageName, arg: arguments);
    }
  }
三、ListView.builder

ListView.builder 是一种构建列表的方法,其中的子 Widget 可以按需构建。但是,与返回静态 Widget 不同的是,它会多次调用(基于 itemCount)一个生成函数,并可在每次调用时返回不同的 Widget。

无限循环列表

ListView.builder(
  itemBuilder: (context, index) {
    return ListTile(
      leading: Icon(Icons.shopping_cart),
      title: Text('product $index'),
      subtitle: Text('price: ${Random().nextInt(100)} USD'),    
    );
  }
)
ListView.builder(
            shrinkWrap: true,
            physics: const NeverScrollableScrollPhysics(),
            itemBuilder: (ctx, index) {
              NewsModel news = accountViewModel.newsList[index];
              return InkWell(
                onTap: () {
                },
                child: Padding(
                  padding: const EdgeInsets.symmetric(vertical: 10),
                  child: Row(
                    children: [
                      Image.asset(
                        "resource/images/temp_news.png",
                        width: 110,
                        height: 70,
                        fit: BoxFit.fill,
                      ),
                      SizedBox(width: 10),
                      Expanded(
                        child: Container(
                          height: 70,
                          child: Column(
                            mainAxisSize: MainAxisSize.max,
                            mainAxisAlignment: MainAxisAlignment.spaceBetween,
                            crossAxisAlignment: CrossAxisAlignment.start,
                            children: [
                              Text(
                                news.title,
                                style: TextStyle(
                                    fontSize: 14, color: Colours.textBlack32),
                                overflow: TextOverflow.ellipsis,
                                softWrap: true,
                                maxLines: 2,
                              ),
                              Text(
                                news.pubDate,
                                style: TextStyle(
                                    fontSize: 12, color: Color(0xFFA3A0A0)),
                              ),
                            ],
                          ),
                        ),
                      )
                    ],
                  ),
                ),
              );
            },
            itemCount: accountViewModel.newsList.length,
          )

解决Flutter ListView 或者SingleChildScrollView 嵌套 ListView.builder滑动冲突

原因
SingleChildScrollView 和 ListView 都有滚动属性physics 他们默认是都是可以滚动的,
ListView 嵌套 ListView.builder 需要后者shrinkWrap = true,不然报错;
解决方式
禁用 ListView 的滚动physics 保留 SingleChildScrollView 的滚动
Listview 执行 physics 属性 new NeverScrollableScrollPhysics(), //禁用

new ListView.builder(
              shrinkWrap: true,
              physics: new NeverScrollableScrollPhysics(),
)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

可可鸭~

想吃糖~我会甜

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值