Flutter 基本組件ListlView

Flutter 列表組件

列表布局是我們項(xiàng)目開(kāi)發(fā)中最常用的一種布局方式脱盲。Flutter 中我們可以通過(guò) ListView 來(lái)定義 列表項(xiàng)广匙,支持垂直和水平方向展示弧可。通過(guò)一個(gè)屬性就可以控制列表的顯示方向嘁字。列表有一下 分類:
1.垂直列表
2.垂直圖文列表
3.水平列表
4.動(dòng)態(tài)列表
5.矩陣式列表

構(gòu)造方法

方法一
默認(rèn)構(gòu)造函數(shù)采用子類的顯式夫椭。此構(gòu)造函數(shù)適用于具有少量(有限個(gè))子項(xiàng)的列表視圖掸掸,因?yàn)闃?gòu)造List需要為可能在列表視圖中顯示的每個(gè)子項(xiàng)執(zhí)行工作,而不僅僅是那些實(shí)際可見(jiàn)的子項(xiàng)

class ListView extends BoxScrollView {
  /// Creates a scrollable, linear array of widgets from an explicit [List].
  ///
  /// This constructor is appropriate for list views with a small number of
  /// children because constructing the [List] requires doing work for every
  /// child that could possibly be displayed in the list view instead of just
  /// those children that are actually visible.
  ///
  /// It is usually more efficient to create children on demand using [new
  /// ListView.builder].
  ///
  /// The `addAutomaticKeepAlives` argument corresponds to the
  /// [SliverChildListDelegate.addAutomaticKeepAlives] property. The
  /// `addRepaintBoundaries` argument corresponds to the
  /// [SliverChildListDelegate.addRepaintBoundaries] property. The
  /// `addSemanticIndexes` argument corresponds to the
  /// [SliverChildListDelegate.addSemanticIndexes] property. None
  /// may be null.
  ListView({
    Key key,
    Axis scrollDirection = Axis.vertical,
    bool reverse = false,
    ScrollController controller,
    bool primary,
    ScrollPhysics physics,
    bool shrinkWrap = false,
    EdgeInsetsGeometry padding,
    this.itemExtent,
    bool addAutomaticKeepAlives = true,
    bool addRepaintBoundaries = true,
    bool addSemanticIndexes = true,
    double cacheExtent,
    List<Widget> children = const <Widget>[],
    int semanticChildCount,
    DragStartBehavior dragStartBehavior = DragStartBehavior.start,
  }) : childrenDelegate = SliverChildListDelegate(
         children,
         addAutomaticKeepAlives: addAutomaticKeepAlives,
         addRepaintBoundaries: addRepaintBoundaries,
         addSemanticIndexes: addSemanticIndexes,
       ),
       super(
         key: key,
         scrollDirection: scrollDirection,
         reverse: reverse,
         controller: controller,
         primary: primary,
         physics: physics,
         shrinkWrap: shrinkWrap,
         padding: padding,
         cacheExtent: cacheExtent,
         semanticChildCount: semanticChildCount ?? children.length,
         dragStartBehavior: dragStartBehavior,
       );

方法二
它構(gòu)造函數(shù)采用IndexedWidgetBuilder它根據(jù)需要構(gòu)建子項(xiàng)蹭秋。此構(gòu)造函數(shù)適用于具有大量(或無(wú)限)子項(xiàng)數(shù)的列表視圖扰付,因?yàn)閮H為實(shí)際可見(jiàn)的子項(xiàng)調(diào)用構(gòu)建器。
長(zhǎng)列表時(shí)采用builder模式仁讨,能提高性能羽莺。不是把所有子控件都構(gòu)造出來(lái),而是在控件viewport加上頭尾的cacheExtent這個(gè)范圍內(nèi)的子Item才會(huì)被構(gòu)造洞豁。在構(gòu)造時(shí)傳遞一個(gè)builder盐固,按需加載是一個(gè)慣用模式,能提高加載性能丈挟。

 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,
    int itemCount,
    bool addAutomaticKeepAlives = true,
    bool addRepaintBoundaries = true,
    bool addSemanticIndexes = true,
    double cacheExtent,
    int semanticChildCount,
    DragStartBehavior dragStartBehavior = DragStartBehavior.start,
  }) : childrenDelegate = SliverChildBuilderDelegate(
         itemBuilder,
         childCount: itemCount,
         addAutomaticKeepAlives: addAutomaticKeepAlives,
         addRepaintBoundaries: addRepaintBoundaries,
         addSemanticIndexes: addSemanticIndexes,
       ),
       super(
         key: key,
         scrollDirection: scrollDirection,
         reverse: reverse,
         controller: controller,
         primary: primary,
         physics: physics,
         shrinkWrap: shrinkWrap,
         padding: padding,
         cacheExtent: cacheExtent,
         semanticChildCount: semanticChildCount ?? itemCount,
         dragStartBehavior: dragStartBehavior,
       );

方式三
它的構(gòu)造函數(shù)有兩個(gè)IndexedWidgetBuilder 構(gòu)建器: itemBuilder根據(jù)需要構(gòu)建子項(xiàng)刁卜,separatorBuilder 類似地構(gòu)建出現(xiàn)在子項(xiàng)之間的分隔子項(xiàng)。此構(gòu)造函數(shù)適用于具有固定數(shù)量子項(xiàng)的列表視圖曙咽。
列表中需要分割線時(shí)蛔趴,可以自定義復(fù)雜的分割線

ListView.separated({
    Key key,
    Axis scrollDirection = Axis.vertical,
    bool reverse = false,
    ScrollController controller,
    bool primary,
    ScrollPhysics physics,
    bool shrinkWrap = false,
    EdgeInsetsGeometry padding,
    @required IndexedWidgetBuilder itemBuilder,
    @required IndexedWidgetBuilder separatorBuilder,
    @required int itemCount,
    bool addAutomaticKeepAlives = true,
    bool addRepaintBoundaries = true,
    bool addSemanticIndexes = true,
    double cacheExtent,
  }) : assert(itemBuilder != null),
       assert(separatorBuilder != null),
       assert(itemCount != null && itemCount >= 0),
       itemExtent = null,
       childrenDelegate = SliverChildBuilderDelegate(
         (BuildContext context, int index) {
           final int itemIndex = index ~/ 2;
           Widget widget;
           if (index.isEven) {
             widget = itemBuilder(context, itemIndex);
           } else {
             widget = separatorBuilder(context, itemIndex);
             assert(() {
               if (widget == null) {
                 throw FlutterError('separatorBuilder cannot return null.');
               }
               return true;
             }());
           }
           return widget;
         },
         childCount: _computeSemanticChildCount(itemCount),
         addAutomaticKeepAlives: addAutomaticKeepAlives,
         addRepaintBoundaries: addRepaintBoundaries,
         addSemanticIndexes: addSemanticIndexes,
         semanticIndexCallback: (Widget _, int index) {
           return index.isEven ? index ~/ 2 : null;
         },
       ),
       super(
         key: key,
         scrollDirection: scrollDirection,
         reverse: reverse,
         controller: controller,
         primary: primary,
         physics: physics,
         shrinkWrap: shrinkWrap,
         padding: padding,
         cacheExtent: cacheExtent,
         semanticChildCount: _computeSemanticChildCount(itemCount),
       );

方式四
構(gòu)造需要SliverChildDelegate提供自定義子項(xiàng)的其他方面的能力。例如桐绒,SliverChildDelegate可以控制用于估計(jì)實(shí)際上不可見(jiàn)的子項(xiàng)大小的算法夺脾。
上面幾種模式基本可以滿足業(yè)務(wù)需求,如果你還想做一些其它設(shè)置(如列表的最大滾動(dòng)范圍)或獲取滑動(dòng)時(shí)每次布局的子Item范圍茉继,可以嘗試custom模式

 const ListView.custom({
    Key key,
    Axis scrollDirection = Axis.vertical,
    bool reverse = false,
    ScrollController controller,
    bool primary,
    ScrollPhysics physics,
    bool shrinkWrap = false,
    EdgeInsetsGeometry padding,
    this.itemExtent,
    @required this.childrenDelegate,
    double cacheExtent,
    int semanticChildCount,
  }) : assert(childrenDelegate != null),
       super(
         key: key,
         scrollDirection: scrollDirection,
         reverse: reverse,
         controller: controller,
         primary: primary,
         physics: physics,
         shrinkWrap: shrinkWrap,
         padding: padding,
         cacheExtent: cacheExtent,
         semanticChildCount: semanticChildCount,
       );

常用屬性

屬性名 功能 值所屬類型
children 列表元素 List<Widget>
scrollDirection Axis.horizontal 水平列表Axis.vertical 垂直列表 Axis
padding 內(nèi)邊距 EdgeInsetsGeometry
resolve 組件反向排序 bool
基本使用
/*
 *listView 的基本使用方法 
 */
class MyListView extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: ListView(
        children: <Widget>[
          ListTile(
            leading: Icon(Icons.phone),
            title: Text(
              "你好數(shù)據(jù)的交換機(jī)",
              style: TextStyle(fontSize: 28.0),
            ),
            subtitle: Text(
              "listview listview",
              style: TextStyle(fontSize: 18.0),
            ),
          ),
          ListTile(
            leading: Icon(Icons.phone),
            title: Text(
              "你好數(shù)據(jù)的交換機(jī)",
              style: TextStyle(fontSize: 28.0),
            ),
            subtitle: Text(
              "listview listview",
              style: TextStyle(fontSize: 18.0),
            ),
          ),
          ListTile(
            leading: Icon(Icons.phone),
            title: Text(
              "你好數(shù)據(jù)的交換機(jī)",
              style: TextStyle(fontSize: 28.0),
            ),
            subtitle: Text(
              "listview listview",
              style: TextStyle(fontSize: 18.0),
            ),
          ),
          ListTile(
            leading: Icon(Icons.phone),
            title: Text(
              "你好數(shù)據(jù)的交換機(jī)",
              style: TextStyle(fontSize: 28.0),
            ),
            subtitle: Text(
              "listview listview",
              style: TextStyle(fontSize: 18.0),
            ),
          ),
          ListTile(
            leading: Icon(Icons.phone),
            title: Text(
              "你好數(shù)據(jù)的交換機(jī)",
              style: TextStyle(fontSize: 28.0),
            ),
            subtitle: Text(
              "listview listview",
              style: TextStyle(fontSize: 18.0),
            ),
          ),ListTile(
            leading: Icon(Icons.phone),
            title: Text(
              "你好數(shù)據(jù)的交換機(jī)",
              style: TextStyle(fontSize: 28.0),
            ),
            subtitle: Text(
              "listview listview",
              style: TextStyle(fontSize: 18.0),
            ),
          ),
          ListTile(
            leading: Icon(Icons.phone),
            title: Text(
              "你好數(shù)據(jù)的交換機(jī)",
              style: TextStyle(fontSize: 28.0),
            ),
            subtitle: Text(
              "listview listview",
              style: TextStyle(fontSize: 18.0),
            ),
          )
        ],
      ),
    );
  }
}

ListView.separated帶有下劃線的ListView

/**
 * 帶有下劃線的listview
 */
class MyListView2 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ListView.separated(
      itemCount: 100,
      itemBuilder: (BuildContext context, int index) {
        if (index.isOdd) {
          return new Container(
            padding: new EdgeInsets.all(15.0),
            child: new Text(
              "builder 奇數(shù) Item " + index.toString(),
              style:
                  new TextStyle(fontSize: 20.0, color: new Color(0xFFFF0000)),
            ),
          );
        } else {
          return new Container(
            padding: new EdgeInsets.all(15.0),
            child: new Text(
              "builder 偶數(shù) Item " + index.toString(),
              style:
                  new TextStyle(fontSize: 20.0, color: new Color(0xFF0000FF)),
            ),
          );
        }
      },
      separatorBuilder: (BuildContext context, int index) {
        return new Divider(
          color: new Color(0xFF888888),
        );
      },
    );
  }
}

ListView.builder 的用法

@override
  Widget build(BuildContext context) {
    return ListView.builder(
      itemCount: 100, //多少數(shù)據(jù)
      itemBuilder: (BuildContext context, int index) {
        if (index.isOdd) {
          return new Container(
            padding: new EdgeInsets.all(15.0),
            child: new Text(
              "builder 奇數(shù) Item " + index.toString(),
              style:
                  new TextStyle(fontSize: 20.0, color: new Color(0xFFFF0000)),
            ),
          );
        } else {
          return new Container(
            padding: new EdgeInsets.all(15.0),
            child: new Text(
              "builder 偶數(shù) Item " + index.toString(),
              style:
                  new TextStyle(fontSize: 20.0, color: new Color(0xFF0000FF)),
            ),
          );
        }
      },
    );
  }
}

ListView.custom 的用法


class MyListView1 extends StatefulWidget {
  @override
  _MyListViewState createState() => _MyListViewState();
}

class _MyListViewState extends State<MyListView1> {
  List<String> items = <String>['1', '2', '3', '4', '5'];

  void _reverse() {
    setState(() {
      items = items.reversed.toList();
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: ListView.custom(
          childrenDelegate: SliverChildBuilderDelegate(
              (BuildContext context, int index) {
                return KeepAlive(
                  data: items[index],
                  key: ValueKey<String>(items[index]),
                );
              },
              childCount: items.length,
              findChildIndexCallback: (Key key) {
                final ValueKey valueKey = key;
                final String data = valueKey.value;
                return items.indexOf(data);
              }),
        ),
      ),
      bottomNavigationBar: BottomAppBar(
        child: Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            FlatButton(
              onPressed: () => _reverse(),
              child: Text('Reverse items'),
            ),
          ],
        ),
      ),
    );
  }
}

網(wǎng)絡(luò)請(qǐng)求

/*
 * 請(qǐng)求網(wǎng)絡(luò)數(shù)據(jù)
 */

class MyListView3 extends StatelessWidget {
  List<Widget> _getListData() {
    var tempList = listData.map((value) {
      return ListTile(
          title: Text(value["title"]),
          leading: Image.network(value["imageUrl"],fit: BoxFit.cover,));
      // return Image(
      //   image:  NetworkImage(value["imageUrl"]),
      //    width: 300.0,
      //   height: 200.0,
      //   fit: BoxFit.cover,
      // );

     
    });

    return tempList.toList();
  }

  @override
  Widget build(BuildContext context) {
    return ListView(children: this._getListData());
  }
}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末咧叭,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子烁竭,更是在濱河造成了極大的恐慌菲茬,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,188評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異婉弹,居然都是意外死亡睬魂,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)镀赌,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)氯哮,“玉大人,你說(shuō)我怎么就攤上這事商佛『砀郑” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,562評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵良姆,是天一觀的道長(zhǎng)肠虽。 經(jīng)常有香客問(wèn)我,道長(zhǎng)玛追,這世上最難降的妖魔是什么税课? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,893評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮痊剖,結(jié)果婚禮上韩玩,老公的妹妹穿的比我還像新娘。我一直安慰自己陆馁,他們只是感情好啸如,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,917評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著氮惯,像睡著了一般叮雳。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上妇汗,一...
    開(kāi)封第一講書(shū)人閱讀 51,708評(píng)論 1 305
  • 那天帘不,我揣著相機(jī)與錄音,去河邊找鬼杨箭。 笑死寞焙,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的互婿。 我是一名探鬼主播捣郊,決...
    沈念sama閱讀 40,430評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼慈参!你這毒婦竟也來(lái)了呛牲?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,342評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤驮配,失蹤者是張志新(化名)和其女友劉穎娘扩,沒(méi)想到半個(gè)月后着茸,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,801評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡琐旁,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,976評(píng)論 3 337
  • 正文 我和宋清朗相戀三年涮阔,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片灰殴。...
    茶點(diǎn)故事閱讀 40,115評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡敬特,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出牺陶,到底是詐尸還是另有隱情擅羞,我是刑警寧澤,帶...
    沈念sama閱讀 35,804評(píng)論 5 346
  • 正文 年R本政府宣布义图,位于F島的核電站,受9級(jí)特大地震影響召烂,放射性物質(zhì)發(fā)生泄漏碱工。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,458評(píng)論 3 331
  • 文/蒙蒙 一奏夫、第九天 我趴在偏房一處隱蔽的房頂上張望怕篷。 院中可真熱鬧,春花似錦酗昼、人聲如沸廊谓。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,008評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)蒸痹。三九已至,卻和暖如春呛哟,著一層夾襖步出監(jiān)牢的瞬間叠荠,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,135評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工扫责, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留榛鼎,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,365評(píng)論 3 373
  • 正文 我出身青樓鳖孤,卻偏偏與公主長(zhǎng)得像者娱,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子苏揣,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,055評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容