7.1-Flutter中列表组件ListView

基于ListView实现水平和垂直方向滚动列表

实现垂直滚动列表

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

const CITY_NAMES = ['北京', '上海', '广州', '深圳', '海南', '杭州', '苏州', '温州'];

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        appBar: AppBar(title: Text('ListView'),),
        body: ListView(
          children: _buildList(),
        ),
      ),
    );
  }

  List<Widget> _buildList() {
    return CITY_NAMES.map((city) => _item(city)).toList();
  }

  Widget _item(String city) {
    return Container(
      height: 80,
      margin: EdgeInsets.only(bottom: 5),
      alignment: Alignment.center,
      decoration: BoxDecoration(color: Colors.teal),
      child: Text(
        city,
        style: TextStyle(color: Colors.white, fontSize: 20),
      ),
    );
  }

}

也可以使用ListView.Builder更加高效的实现列表(适用于动态列表或者数据来给你较大时)

      home: Scaffold(
        appBar: AppBar(title: Text('ListView'),),
        body: ListView.builder(
          itemCount: CITY_NAMES.length,
          itemBuilder: (BuildContext context, int position) {
            return _buildList()[position];
          },
        ),
      ),

实现水平滚动列表

水平滚动只需要为ListView添加scrollDirection: Axis.horizontal参数即可

      home: Scaffold(
        appBar: AppBar(title: Text('ListView'),),
        body: ListView(
          scrollDirection: Axis.horizontal,
          children: _buildList(),
        ),
      ),
  • 为ListView设置高度需要对ListView外层Container设置高度

基于ExpansionTitle实现可展开的列表

ExpansionTitle基本知识

const ExpansionTile({
    Key key,
    this.leading,//标题左侧要展示的widget
    @required this.title,//要展示的标题widget(是整个标题父控件)
    this.backgroundColor,//背景
    this.onExpansionChanged,//列表展开收起的回调函数
    this.children = const <Widget>[],//列表展开时显示的widget
    this.trailing,//标题右侧要展示的widget
    this.initiallyExpanded = false,//是否默认状态下展开
  }) : assert(initiallyExpanded != null),
       super(key: key);
  • 数据要求

    const CITY_NAMES = {
      '北京': ['东城区', '西城区', '丰台区', '海淀区', '房山区'],
      '上海': ['黄埔区', '徐汇区', '虹口区'],
      '杭州': ['上城区', '下城区']
    };
    
  • ExpansionTitle

    import 'package:flutter/material.dart';
    
    void main() => runApp(MyApp());
    
    const CITY_NAMES = {
      '北京': ['东城区', '西城区', '丰台区', '海淀区', '房山区'],
      '上海': ['黄埔区', '徐汇区', '虹口区'],
      '杭州': ['上城区', '下城区']
    };
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'ExpansionTile Demo',
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: Scaffold(
            appBar: AppBar(title: Text('ListView'),),
            body: ListView(
              children: _buildList(),
            ),
          ),
        );
      }
    
      List<Widget> _buildList() {
        List<Widget> widgets = [];
        CITY_NAMES.keys.forEach((key) {
          widgets.add(_item(key, CITY_NAMES[key]));
        });
        return widgets;
      }
    
      Widget _item(String city, List<String> subCities) {
        return ExpansionTile(
          title: Text(
            city,
            style: TextStyle(color: Colors.black54, fontSize: 20),
          ),
          children: subCities.map((subCities) => _buildSub(subCities)).toList(),
        );
      }
    
      Widget _buildSub(String subCity) {
        return FractionallySizedBox(//可伸缩(如果不设置FractionallySizedBox,子列表宽度无法撑满屏幕)
          widthFactor: 1,
          child: Container(
            height: 50,
            margin: EdgeInsets.only(bottom: 5),
            decoration: BoxDecoration(color: Colors.lightBlueAccent),
            child: Text(subCity),
          ),
        );
      }
    
    }
    
    image

基于GridView实现网格列表

GridView时flutter中用于展示网格布局风格的widget,通常使用GridView.count构造函数来创建一个GridView

与ListView用法一直,只需要使用GridView.count构建即可

      home: Scaffold(
        appBar: AppBar(title: Text('ListView'),),
        body: GridView.count(
          crossAxisCount: 2,//列数
          children: _buildList(),
        ),
      ),
image

高级功能列表下拉刷新与上拉加载更多

实现下拉刷新

使用RefreshIndicator实现列表的下拉刷新

实现上拉加载

借助ScrollController,为列表设置controller参数,通过ScrollController监听列表滚动的位置,实现加载更多功能

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

List<String> cityNames = [
  '北京', '上海', '广州', '深圳', '海南', '杭州', '苏州', '温州', '泉州', '保定', '郑州', '唐山', '东京'];

class MyApp extends StatefulWidget {

  @override
  _MyAppState createState() => _MyAppState();

}

class _MyAppState extends State<MyApp> {

  ScrollController _scrollController = ScrollController();

  @override
  void initState() {
    _scrollController.addListener(() {
      if (_scrollController.position.pixels ==
          _scrollController.position.maxScrollExtent) { //当前位置等于可滚动位置
        _loadData();
      }
    });
    super.initState();
  }

  @override
  void dispose() {
    //在声明周期结束的时候将监听移除
    _scrollController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: '下拉刷新',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
          appBar: AppBar(title: Text('ListView'),),
          body: RefreshIndicator(
              child: ListView(
                controller: _scrollController,
                children: _buildList(),
              ),
              onRefresh: _handleRefresh)
      ),
    );
  }


  List<Widget> _buildList() {
    return cityNames.map((city) => _item(city)).toList();
  }

  Widget _item(String city) {
    return Container(
      height: 80,
      margin: EdgeInsets.only(bottom: 5),
      alignment: Alignment.center,
      decoration: BoxDecoration(color: Colors.teal),
      child: Text(
        city,
        style: TextStyle(color: Colors.white, fontSize: 20),
      ),
    );
  }

  Future<Null> _handleRefresh() async {
    await Future.delayed(Duration(seconds: 2));
    setState(() {
      cityNames = cityNames.reversed.toList();
    });
    return null;
  }

  _loadData() async {
    await Future.delayed(Duration(milliseconds: 200));
    setState(() {
      List<String> list = new List <String>.from(cityNames);
      list.addAll(cityNames);
      cityNames = list;
    });
  }

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

推荐阅读更多精彩内容

  • 1.Row 线性布局,将children排成一行,主轴为水平方向,交叉轴为垂直方向。 textDirection:...
    hxljy阅读 786评论 0 5
  • 简单列举总结一下常用的布局widget。Flutter有丰富的layout组件库。其中有一些是常用库。下面的wid...
    charmingcheng阅读 599评论 0 0
  • 我们的距离并不远 因为我能感觉到你的存在 或许我们在哪儿见过 只是不知道也不记得彼此的面容 也许在餐厅 也许在槐树...
    水上南风阅读 274评论 1 0
  • 爸爸每天送我去入园 小区右拐向前行 路旁小树来相伴 爸爸笑言来相随 今天妈妈送我去入园 小区左向电车开 我问妈妈为...
    轻轻地走在路上阅读 195评论 0 0
  • 最近发现了一个叫pointer-events的css属性,是一个与javascript有关的属性,pointer-...
    呂鳳先阅读 820评论 1 0