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

在以前講Layout Widget的文章中,咱們掌握了基於不一樣的場景適當的選擇不一樣的Widget來完成咱們的佈局要求,可是關於長列表的數據展現咱們並無作展開介紹,而長列表的身影幾乎出如今平常生活中的任意一款APP中,鑑於它的重要性,因此我想單獨做爲一個章節來說解長列表Widget---ListView&GirdViewjava

1.ListView

1.1 ListView簡單列表

看下ListView的構造方法,而後咱們用listview來完成一個簡單列表緩存

ListView({
    Key key,
    Axis scrollDirection: Axis.vertical,//滾動方向
    bool reverse: false,//是否反向顯示數據
    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展現長列表佈局的時候,大多數狀況下咱們是不知道長列表一共有多少個元素,即便是能知道,咱們重複性的把每一個類似的佈局都寫一遍,也幾乎讓人崩潰。app

沒錯,Flutter確定給咱們提供了像原生Android寫Adapter同樣的方式,咱們能夠提早寫好公共的Item佈局,而後經過ListView.builder()或者ListView.custom()方式自動生成長列表,ListView.builder()ListView.custom()的用法基本相同,只不過custom能夠根據本身的須要控制Item顯示方式,如Item顯示大小。less

1.2 可複用的ListView長列表

下面我帶你們一塊兒看下ListView.builder()的構造方法,而後使用ListView.builder寫個簡單的樣式代碼,至於ListView.custom的用法我會在下面介紹GridView的時候講到,讀者可參考Listview.bulider自行測試。ide

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數量
    bool addAutomaticKeepAlives: true,
    bool addRepaintBoundaries: true,
  })

複製代碼

從ListView.bulider的構造方法咱們能夠看出,它只比上述咱們直接使用的ListView的構造方法多了兩個參數,也正是這兩個參數簡化了咱們對長列表的操做佈局

itemCount::被展現的Item的數量 itemBuilder:被展現的Item的構造者(這裏讀者能夠它類比成原生Android的Adapter)測試

下面咱們來看下效果圖: ui

長列表
樣例代碼

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部分的講解。this

2.GridView

跟原生Android同樣,GridView知足了咱們全部使用表格佈局的場景,固然若是GridView在每行或者每列都只顯示一個Item的時候又至關於ListView的使用場景。可是回到Flutter上GridView的用法又跟ListView使用相似,能夠直接new對象的方式生成簡單的表格佈局,也能夠像ListView那樣經過builder()和custom()方法來建立可複用的對象spa

構造方法

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參數,來配置一行(列)有幾個Item和Item的間隔。

gridDelegate參數說明

gridDelegate可接收兩種參數類型:

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

先來看下GridView的效果圖,關於gridDelegate的區別我在代碼裏作了註釋講解,這裏就不在多贅述了讀者可結合代碼自行理解。

效果圖

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, //根據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中我帶你們使用下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()方法來建立可複用對象,從而擴展了ListView跟GridView的靈活性,就像咱們原生Android同樣,把可複用的佈局抽象成Adapter的形式,可是或許你總以爲關於列表還少點什麼,下拉刷新?加載更多?

相關文章
相關標籤/搜索