Flutter 11: 图解 ListView 的多种绑定方式

      小菜昨天刚学习了一下底部状态栏 BottomNavigationBar 的基本使用方法,今天学习一下 ListView 的基本用法。
      小菜觉得 Flutter 中 ListView 这个控件很强大,它兼顾了 Android 中的 ScrollView 和 ListView 两个控件的效果,既可以当列表用也可以充当可滑动布局。小菜今天主要测试作为普通列表时的基本用法。

效果图1.jpg

效果图2.jpg

列表 item -> ListTile

      Flutter 很贴心的提供了一种常见的列表 item 样式,可以包括前后图标以及大小标题的样式;小菜特意了解了一下 ListTile 的基本属性,如下:

const ListTile({
    Key key,
    this.leading,              // item 前置图标
    this.title,                // item 标题
    this.subtitle,             // item 副标题
    this.trailing,             // item 后置图标
    this.isThreeLine = false,  // item 是否三行显示
    this.dense,                // item 直观感受是整体大小
    this.contentPadding,       // item 内容内边距
    this.enabled = true,
    this.onTap,                // item onTap 点击事件
    this.onLongPress,          // item onLongPress 长按事件
    this.selected = false,     // item 是否选中状态
})

      Tips: 小菜对 dense 属性理解不是很好,直观的感觉是 dense 为 true 时整体会小一些,文字更为明显,就像整体分辨率变高;如下图:

dense 为 false.jpg
dense 为 true.jpg

列表 -> ListView

      Flutter 中 ListView 用法与 Android 中类似,首先添加数据,之后绑定列表;Flutter 中绑定列表有四种方式,分别是 默认 List / ListView.builder / ListView.separated / ListView.custom;小菜主要对前三种方式逐一测试;如图:

      无论是用那种绑定数据的方式首先第一步都要添加数据,小菜测试基本样式包括 item 前置图标(leading)、标题文字(title)、后置图标(trailing),并设置了基本的 onTap() 方法;如下:

List<String> strItems = <String>[
    '图标 -> keyboard', '图标 -> print',
    '图标 -> router', '图标 -> pages',
    '图标 -> zoom_out_map', '图标 -> zoom_out',
    '图标 -> youtube_searched_for', '图标 -> wifi_tethering',
    '图标 -> wifi_lock', '图标 -> widgets',
    '图标 -> weekend', '图标 -> web',
    '图标 -> accessible', '图标 -> ac_unit',
];

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

Widget buildListData(BuildContext context, String strItem, Icon iconItem) {
    return new ListTile(
      isThreeLine: false,
      leading: iconItem,
      title: new Text(strItem),
      trailing: new Icon(Icons.keyboard_arrow_right),
      onTap: () {
        showDialog(
          context: context,
          builder: (BuildContext context) {
            return new AlertDialog(
              title: new Text(
                'ListViewDemo',
                style: new TextStyle(
                  color: Colors.black54,
                  fontSize: 18.0,
                ),
              ),
              content: new Text('您选择的item内容为:$strItem'),
            );
          },
        );
      },
    );
}

1. 默认 List

      小菜理解默认 List 方式,是把数据 Iterable 添加到列表中,之后直接添加到 ListView 即可;如下:

List<Widget> _list = new List();
for (int i = 0; i < strItems.length; i++) {
    _list.add(buildListData(context, strItems[i], iconItems[i]));
}
// 添加分割线
var divideList =
        ListTile.divideTiles(context: context, tiles: _list).toList();
body: new Scrollbar(
    child: new ListView(
        // 添加ListView控件
//        children: _list,    // 无分割线
        children: divideList, // 添加分割线
    ),
);

      Tips: 如果需要设置分割线,需要对列表 item 添加处理,ListTile.divideTiles

2. ListView.builder

      小菜理解 builder 方式很像对话框类型逐个添加需要的属性;需要在 builder 中添加列表数据;而添加分割线的方式更让小菜体会到 Flutter 一切都是 widget 思想的重要性,如下:

// 没有分割线
child: new ListView.builder(
    itemCount: iconItems.length,  // 数据长度
    itemBuilder: (context, item) {
        return buildListData(context, strItems[item], iconItems[item]);
    },
),

// 添加分割线
child: new ListView.builder(
    itemCount: iconItems.length,
    itemBuilder: (context, item) {
        return new Container(
            child: new Column(
              children: <Widget>[
                buildListData(context, strItems[item], iconItems[item]),
                new Divider()
              ],
            ),
        );
    },
),

3. ListView.separated

      小菜对 separated 方式最大的理解是有直接的分隔符设置方式,对分隔符列表应用更实用;设置 separatorBuilder 属性即可;如下:

child: new ListView.separated(
    itemCount: iconItems.length,
    separatorBuilder: (BuildContext context, int index) => new Divider(),  // 添加分割线
    itemBuilder: (context, item) {
        return buildListData(context, strItems[item], iconItems[item]);
    },
),

4. ListView.custom

      小菜暂时不对本加载方式做实例尝试,小菜理解 ListView.custom 更适合对 item 中含有子类 item,并对子类 item 的显隐性有更多操作时使用该方式更好;在以后的尝试中小菜会单独对这种方式进行测试整理。

主要源码

List<Widget> _list = new List();

@override
Widget build(BuildContext context) {
    for (int i = 0; i < strItems.length; i++) {
      _list.add(buildListData(context, strItems[i], iconItems[i]));
    }
    var divideList =
        ListTile.divideTiles(context: context, tiles: _list).toList();
    return new Scaffold(
      body: new Scrollbar(
        // 默认方式 List
//        child: new ListView(
//          children: divideList, //添加ListView控件
//        ),
        // ListView.separated 方式
//        child: new ListView.separated(
//          itemCount: iconItems.length,
//          separatorBuilder: (BuildContext context, int index) => new Divider(),
//          itemBuilder: (context, item) {
//            return buildListData(context, strItems[item], iconItems[item]);
//          },
//        ),
        // ListView.builder 方式
        child: new ListView.builder(
          itemCount: iconItems.length,
          itemBuilder: (context, item) {
            return new Container(
              child: new Column(
                children: <Widget>[
                  buildListData(context, strItems[item], iconItems[item]),
                  new Divider()
                ],
              ),
            );
          },
        ),
//        child: new ListView.custom(
//
//        ),
      ),
    );
}
无分割线.jpg
有分割线.jpg
点击事件.jpg

      Tips: 列表中有一个属性很有意思:reverse 是否反转,如果设为 true,列表默认滑倒底部而且数据也是倒叙排列;若设为 false,则一切正常。其他很多属性也很有特点,小菜还没来得及深入探究。

      GitHub Demo


      小菜刚接触 Flutter 时间不长,还有很多不清楚和不理解的地方,如果又不对的地方还希望多多指出。

来源:阿策小和尚

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,968评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,601评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,220评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,416评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,425评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,144评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,432评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,088评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,586评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,028评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,137评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,783评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,343评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,333评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,559评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,595评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,901评论 2 345

推荐阅读更多精彩内容

  • ¥开启¥ 【iAPP实现进入界面执行逐一显】 〖2017-08-25 15:22:14〗 《//首先开一个线程,因...
    小菜c阅读 6,358评论 0 17
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,601评论 18 139
  • 印象欧罗巴------小欧的第一次旅行 带着N年的梦想,我终于趟上了这片美丽的土地。。。。。。 丹麦的帅司机LEO...
    玲玲100阅读 488评论 0 1
  • 1、前言 我们都知道将图片保存到本地的操作,但是如何将本地的图片保存到相册。有几种不同的方法,下面分别讲述这几种方...
    AndroidHint阅读 10,083评论 2 5
  • 秋意起 万草枯 临行无柳可留 渔舟载一轮清月孤 好沉 路漫漫 尘飞扬 病马瘦笛破衣 当年宝剑已藏 江湖梦碎 侠客是...
    人造月球阅读 242评论 3 6