Flutter入門進階之旅(十四)ListView&GridView

在之前講Layout Widget的文章中,我們掌握了基于不同的場景適當?shù)倪x擇不同的Widget來完成我們的布局要求茬射,但是關于長列表的數(shù)據(jù)展示我們并沒有做展開介紹,而長列表的身影幾乎出現(xiàn)在日常生活中的任意一款APP中,鑒于它的重要性焕檬,所以我想單獨作為一個章節(jié)來講解長列表Widget---ListView&GirdView宴霸。

1.ListView

1.1 ListView簡單列表

看下ListView的構造方法囱晴,然后我們用listview來完成一個簡單列表

ListView({
    Key key,
    Axis scrollDirection: Axis.vertical,//滾動方向
    bool reverse: false,//是否反向顯示數(shù)據(jù)
    ScrollController controller,
    bool primary,
    ScrollPhysics physics,//物理滾動
    bool shrinkWrap: false,
    EdgeInsetsGeometry padding,
    this.itemExtent,//item有效范圍
    bool addAutomaticKeepAlives: true,//自動保存視圖緩存
    bool addRepaintBoundaries: true,//添加重繪邊界
    List<Widget> children: const <Widget>[],
  })

ListView簡單列表

上述效果圖樣例代碼

import 'package:flutter/material.dart';

void main() {
  runApp(new MaterialApp(
    title: "ListView",
    home: new MyApp(),
  ));
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
        appBar: new AppBar(
          title: new Text("ListView"),
        ),
        body: ListView(
          scrollDirection: Axis.vertical, //控制列表方向
          children: <Widget>[
            new Container(
              width: 100.0,
              height: 100.0,
              color: Colors.lightBlue,
            ),
            new Container(
              width: 100.0,
              height: 100.0,
              color: Colors.red,
            ),
            new Container(
              width: 100.0,
              height: 100.0,
              color: Colors.deepPurple,
            ),
            new Container(
              width: 100.0,
              height: 100.0,
              color: Colors.yellow,
            ),
            new Container(
              width: 100.0,
              height: 100.0,
              color: Colors.lightBlue,
            ),
            new Container(
              width: 100.0,
              height: 100.0,
              color: Colors.red,
            ),
            new Container(
              width: 100.0,
              height: 100.0,
              color: Colors.deepPurple,
            ),
            new Container(
              width: 100.0,
              height: 100.0,
              color: Colors.lightBlue,
            ),
            new Container(
              width: 100.0,
              height: 100.0,
              color: Colors.red,
            ),
            new Container(
              width: 100.0,
              height: 100.0,
              color: Colors.deepPurple,
            ),
            new Container(
              width: 100.0,
              height: 100.0,
              color: Colors.lightBlue,
            ),
          ],
        ));
  }
}

上述代碼中我們利用ListView做了一個簡單的長列表布局,通過給children: <Widget>[]傳入我們要展示的子Widget來完成列表渲染瓢谢,理論上我們可以傳入任意多的子Widget畸写,但是這點使用起來跟Column沒有太大差別,這顯然是不符合我們的預期的氓扛,因為我們在使用ListView展示長列表布局的時候枯芬,大多數(shù)情況下我們是不知道長列表一共有多少個元素,即使是能知道采郎,我們重復性的把每個相似的布局都寫一遍千所,也幾乎讓人崩潰。

沒錯蒜埋,F(xiàn)lutter肯定給我們提供了像原生Android寫Adapter一樣的方式淫痰,我們可以提前寫好公共的Item布局,然后通過ListView.builder()或者ListView.custom()方式自動生成長列表整份,ListView.builder()ListView.custom()的用法基本相同待错,只不過custom可以根據(jù)自己的需要控制Item顯示方式,如Item顯示大小烈评。

1.2 可復用的ListView長列表

下面我?guī)Т蠹乙黄鹂聪翷istView.builder()的構造方法火俄,然后使用ListView.builder寫個簡單的樣式代碼,至于ListView.custom的用法我會在下面介紹GridView的時候講到讲冠,讀者可參考Listview.bulider自行測試瓜客。

ListView.builder({
    Key key,
    Axis scrollDirection: Axis.vertical,
    bool reverse: false,
    ScrollController controller,
    bool primary,
    ScrollPhysics physics,
    bool shrinkWrap: false,
    EdgeInsetsGeometry padding,
    this.itemExtent,
    @required IndexedWidgetBuilder itemBuilder,//item構建者
    int itemCount,//item數(shù)量
    bool addAutomaticKeepAlives: true,
    bool addRepaintBoundaries: true,
  })

從ListView.bulider的構造方法我們可以看出,它只比上述我們直接使用的ListView的構造方法多了兩個參數(shù),也正是這兩個參數(shù)簡化了我們對長列表的操作

itemCount::被展示的Item的數(shù)量
itemBuilder:被展示的Item的構造者(這里讀者可以它類比成原生Android的Adapter)

下面我們來看下效果圖:

長列表

樣例代碼

import 'package:flutter/material.dart';

void main() {
  runApp(new MaterialApp(
    title: "ListView",
    home: new MyApp(),
  ));
}

class MyApp extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => MyState();
}

class MyState extends State {
  List<ItemEntity> entityList = [];

  @override
  void initState() {
    super.initState();
    for (int i = 0; i < 30; i++) {
      entityList.add(ItemEntity("Item  $i", Icons.accessibility));
    }
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
        appBar: new AppBar(
          title: new Text("ListView"),
        ),
        body: ListView.builder(
          itemBuilder: (BuildContext context, int index) {
            return ItemView(entityList[index]);
          },
          itemCount: entityList.length,
        ));
  }
}

/**
 * 渲染Item的實體類
 */
class ItemEntity {
  String title;
  IconData iconData;

  ItemEntity(this.title, this.iconData);
}

/**
 * ListView builder生成的Item布局忆家,讀者可類比成原生Android的Adapter的角色
 */
class ItemView extends StatelessWidget {
  ItemEntity itemEntity;

  ItemView(this.itemEntity);

  @override
  Widget build(BuildContext context) {
    return Flex(
      direction: Axis.vertical,
      children: <Widget>[
        ListTile(
            leading: Icon(itemEntity.iconData), title: Text(itemEntity.title),subtitle: Text('長列表')),
        SizedBox(
          height: 0.2,
          child: Container(
            color: Colors.black,
          ),
        )
      ],
    );
  }
}

上述代碼中的邏輯讀者大部分都可以自解的犹菇,我就不多做贅述了,下面我們進入本篇分享的第二部分芽卿,關于GridView部分的講解揭芍。

2.GridView

跟原生Android一樣,GridView滿足了我們所有使用表格布局的場景卸例,當然如果GridView在每行或者每列都只顯示一個Item的時候又相當于ListView的使用場景称杨。但是回到Flutter上GridView的用法又跟ListView使用類似,可以直接new對象的方式生成簡單的表格布局筷转,也可以像ListView那樣通過builder()和custom()方法來創(chuàng)建可復用的對象

構造方法

GridView({
    Key key,
    Axis scrollDirection: Axis.vertical,
    bool reverse: false,
    ScrollController controller,
    bool primary,
    ScrollPhysics physics,
    bool shrinkWrap: false,
    EdgeInsetsGeometry padding,
    @required this.gridDelegate,   //控制GridView顯示方式
    bool addAutomaticKeepAlives: true,
    bool addRepaintBoundaries: true,
    List<Widget> children: const <Widget>[],
  })

上面提到GridView跟ListView使用方法類似姑原,但是GridView不同于ListView的是它可以在一行或者一列顯示多個Item,所以GridView的構造方法對比ListView多了一個gridDelegate參數(shù)呜舒,來配置一行(列)有幾個Item和Item的間隔锭汛。

gridDelegate參數(shù)說明

gridDelegate可接收兩種參數(shù)類型:

  • SliverGridDelegateWithFixedCrossAxisCount可以直接指定每行(列)顯示多少個Item
  • SliverGridDelegateWithMaxCrossAxisExtent會根據(jù)GridView的寬度和你設置的每個的寬度來自動計算沒行顯示多少個Item

先來看下GridView的效果圖,關于gridDelegate的區(qū)別我在代碼里做了注釋講解袭蝗,這里就不在多贅述了讀者可結合代碼自行理解唤殴。

效果圖

GridView

樣例代碼

import 'package:flutter/material.dart';

void main() {
  runApp(new MaterialApp(
    title: "ListView",
    home: new MyApp(),
  ));
}

class MyApp extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => MyState();
}
class MyState extends State {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
        appBar: new AppBar(
          title: new Text("ListView"),
        ),
        body: new GridView(
//          gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
//              crossAxisCount: 3, //固定顯示三個
//              mainAxisSpacing: 10,
//              crossAxisSpacing: 10),
          gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
              maxCrossAxisExtent: 100, //根據(jù)maxCrossAxisExtent的值對比屏幕的真實寬度,決定一行或者一列顯示多少個Item
              mainAxisSpacing: 10,
              crossAxisSpacing: 10),
          children: <Widget>[
            Container(
                child: Icon(Icons.adb, size: 60),
                color: Colors.deepOrangeAccent),
            Container(
                child: Icon(Icons.adb, size: 60),
                color: Colors.deepOrangeAccent),
            Container(
                child: Icon(Icons.adb, size: 60),
                color: Colors.deepOrangeAccent),
            Container(
                child: Icon(Icons.adb, size: 60),
                color: Colors.deepOrangeAccent),
            Container(
                child: Icon(Icons.adb, size: 60),
                color: Colors.deepOrangeAccent),
            Container(
                child: Icon(Icons.adb, size: 60),
                color: Colors.deepOrangeAccent),
            Container(
                child: Icon(Icons.adb, size: 60),
                color: Colors.deepOrangeAccent),
            Container(
                child: Icon(Icons.adb, size: 60),
                color: Colors.deepOrangeAccent),
          ],
        ));
  }
}

在本篇分享的第一部分我們介紹ListView的時候提到到腥,為了復用Item布局朵逝,我們可以通過builder()或者custom來生成Item布局,在ListView中我們使用的是builder()的方式生成的可復用的布局乡范,在gridView中我?guī)Т蠹沂褂孟?code>custom()配名,其實listView跟GridView使用類似,無非就是布局排列不同而已晋辆。

效果圖

GridView

樣例代碼

import 'package:flutter/material.dart';

void main() {
  runApp(new MaterialApp(
    title: "ListView",
    home: new MyApp(),
  ));
}

class MyApp extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => MyState();
}

class MyState extends State {
  List<ItemEntity> entityList = [];

  @override
  void initState() {
    super.initState();
    for (int i = 0; i < 30; i++) {
      entityList.add(ItemEntity("Item  $i", Icons.accessibility));
    }
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
        appBar: new AppBar(
          title: new Text("GridView"),
        ),
        body: GridView.custom(
            gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
              crossAxisCount: 3,
              crossAxisSpacing: 10,
              mainAxisSpacing: 10,
            ),
            childrenDelegate: SliverChildBuilderDelegate(
              (BuildContext context, int index) {
                return ItemView(entityList[index]);
              },
              childCount: entityList.length,
            )));
  }
}

/**
 * 渲染Item的實體類
 */
class ItemEntity {
  String title;
  IconData iconData;

  ItemEntity(this.title, this.iconData);
}

/**
 * GridView builder生成的Item布局渠脉,讀者可類比成原生Android的Adapter的角色
 */
class ItemView extends StatelessWidget {
  ItemEntity itemEntity;

  ItemView(this.itemEntity);

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      child: Flex(
        direction: Axis.vertical,
        children: <Widget>[
          Icon(
            itemEntity.iconData,
            size: 60,
          ),
          Text(itemEntity.title),
        ],
      ),
      onTap: () {
        Scaffold.of(context).showSnackBar(
            new SnackBar(content: Text("點擊了${itemEntity.title}")));
      },
    );
  }
}

總結

通過本篇博文我們了解到ListView跟GridView都可以直接用new對象的方式生成列表布局,一個用于表格布局栈拖,另一個用于長列表布局连舍,也可以使用new 或者builder()和custom()方法來創(chuàng)建可復用對象,從而擴展了ListView跟GridView的靈活性涩哟,就像我們原生Android一樣索赏,把可復用的布局抽象成Adapter的形式,但是或許你總覺得關于列表還少點什么贴彼,下拉刷新潜腻?加載更多?

下一篇:Flutter入門進階之旅(十五)ListView下拉刷新&上拉加載更多

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末器仗,一起剝皮案震驚了整個濱河市融涣,隨后出現(xiàn)的幾起案子童番,更是在濱河造成了極大的恐慌,老刑警劉巖威鹿,帶你破解...
    沈念sama閱讀 222,865評論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件剃斧,死亡現(xiàn)場離奇詭異,居然都是意外死亡忽你,警方通過查閱死者的電腦和手機幼东,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,296評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來科雳,“玉大人根蟹,你說我怎么就攤上這事≡忝兀” “怎么了简逮?”我有些...
    開封第一講書人閱讀 169,631評論 0 364
  • 文/不壞的土叔 我叫張陵,是天一觀的道長尿赚。 經常有香客問我散庶,道長,這世上最難降的妖魔是什么吼畏? 我笑而不...
    開封第一講書人閱讀 60,199評論 1 300
  • 正文 為了忘掉前任督赤,我火速辦了婚禮,結果婚禮上泻蚊,老公的妹妹穿的比我還像新娘。我一直安慰自己丑婿,他們只是感情好性雄,可當我...
    茶點故事閱讀 69,196評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著羹奉,像睡著了一般秒旋。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上诀拭,一...
    開封第一講書人閱讀 52,793評論 1 314
  • 那天迁筛,我揣著相機與錄音,去河邊找鬼耕挨。 笑死细卧,一個胖子當著我的面吹牛,可吹牛的內容都是我干的筒占。 我是一名探鬼主播贪庙,決...
    沈念sama閱讀 41,221評論 3 423
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼翰苫!你這毒婦竟也來了止邮?” 一聲冷哼從身側響起这橙,我...
    開封第一講書人閱讀 40,174評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎导披,沒想到半個月后屈扎,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 46,699評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡撩匕,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,770評論 3 343
  • 正文 我和宋清朗相戀三年鹰晨,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片滑沧。...
    茶點故事閱讀 40,918評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡并村,死狀恐怖,靈堂內的尸體忽然破棺而出滓技,到底是詐尸還是另有隱情哩牍,我是刑警寧澤,帶...
    沈念sama閱讀 36,573評論 5 351
  • 正文 年R本政府宣布令漂,位于F島的核電站膝昆,受9級特大地震影響,放射性物質發(fā)生泄漏叠必。R本人自食惡果不足惜荚孵,卻給世界環(huán)境...
    茶點故事閱讀 42,255評論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望纬朝。 院中可真熱鬧收叶,春花似錦、人聲如沸共苛。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,749評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽隅茎。三九已至澄峰,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間辟犀,已是汗流浹背俏竞。 一陣腳步聲響...
    開封第一講書人閱讀 33,862評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留堂竟,地道東北人魂毁。 一個月前我還...
    沈念sama閱讀 49,364評論 3 379
  • 正文 我出身青樓,卻偏偏與公主長得像跃捣,于是被迫代替她去往敵國和親漱牵。 傳聞我的和親對象是個殘疾皇子肌割,可洞房花燭夜當晚...
    茶點故事閱讀 45,926評論 2 361

推薦閱讀更多精彩內容

  • 一缩麸、適用場景 ListViewListview是一個很重要的組件翼悴,它以列表的形式根據(jù)數(shù)據(jù)的長自適應展示具體內容,用...
    Geeks_Liu閱讀 10,684評論 1 28
  • 國慶后面兩天在家學習整理了一波flutter全度,基本把能擼過能看到的代碼都過了一遍,此文篇幅較長闻镶,建議保存(star...
    Nealyang閱讀 4,348評論 1 17
  • 對于持之以恒的做一件事兒铆农,一周應該是最小的計數(shù)單位吧牺氨!當然,那些愛情上頭墩剖,一見鐘情猴凹,以秒來計算時間的除外,細數(shù)自己...
    灰玫瑰汪然閱讀 497評論 8 11
  • 我最近看到了一句話岭皂,他說:“不管將來你的身邊有誰郊霎,也不可能存在一個人完完全全明白你的所思所想,哪怕是你未來的伴侶也...
    暖心怪人閱讀 135評論 0 0
  • 昨天傍晚吃飯爷绘,奶奶跟我說暖小姐在家說的那些的話书劝,笑到不行。奶奶記錄了部分土至,邊讀她在一邊邊笑购对。大體是因為她自己...
    小豬天堂閱讀 117評論 2 1