Flutter開發(fā) -- [09 - ListView]

一. ListView組件

移動端數(shù)據(jù)量比較大時,我們都是通過列表來進行展示的,比如商品數(shù)據(jù)、聊天列表、通信錄、朋友圈等。

在Android中,我們可以使用ListView或RecyclerView來實現(xiàn),在iOS中,我們可以通過UITableView來實現(xiàn)。

在Flutter中,我們也有對應(yīng)的列表Widget,就是ListView。

1.1. ListView基礎(chǔ)

1.1.1 ListView基本使用

ListView可以沿一個方向(垂直或水平方向,默認是垂直方向)來排列其所有子Widget。

一種最簡單的使用方式是直接將所有需要排列的子Widget放在ListView的children屬性中即可。

我們來看一下直接使用ListView的代碼演練:

  • 為了讓文字之間有一些間距,我使用了Padding Widget
class MyHomeBody extends StatelessWidget {
  final TextStyle textStyle = TextStyle(fontSize: 20, color: Colors.redAccent);

  @override
  Widget build(BuildContext context) {
    return ListView(
      children: <Widget>[
        Padding(
          padding: const EdgeInsets.all(8.0),
          child: Text("人的一切痛苦,本質(zhì)上都是對自己無能的憤怒。", style: textStyle),
        ),
        Padding(
          padding: const EdgeInsets.all(8.0),
          child: Text("人活在世界上,不可以有偏差;而且多少要費點勁兒,才能把自己保持到理性的軌道上。", style: textStyle),
        ),
        Padding(
          padding: const EdgeInsets.all(8.0),
          child: Text("我活在世上,無非想要明白些道理,遇見些有趣的事。", style: textStyle),
        )
      ],
    );
  }
}

1.1.2. ListTile的使用

在開發(fā)中,我們經(jīng)常見到一種列表,有一個圖標或圖片(Icon),有一個標題(Title),有一個子標題(Subtitle),還有尾部一個圖標(Icon)。

這個時候,我們可以使用ListTile來實現(xiàn):

class MyHomeBody extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return ListView(
      children: <Widget>[
        ListTile(
          leading: Icon(Icons.people, size: 36,),
          title: Text("聯(lián)系人"),
          subtitle: Text("聯(lián)系人信息"),
          trailing: Icon(Icons.arrow_forward_ios),
        ),
        ListTile(
          leading: Icon(Icons.email, size: 36,),
          title: Text("郵箱"),
          subtitle: Text("郵箱地址信息"),
          trailing: Icon(Icons.arrow_forward_ios),
        ),
        ListTile(
          leading: Icon(Icons.message, size: 36,),
          title: Text("消息"),
          subtitle: Text("消息詳情信息"),
          trailing: Icon(Icons.arrow_forward_ios),
        ),
        ListTile(
          leading: Icon(Icons.map, size: 36,),
          title: Text("地址"),
          subtitle: Text("地址詳情信息"),
          trailing: Icon(Icons.arrow_forward_ios),
        )
      ],
    );
  }
}

1.1.3. 垂直方向滾動

我們可以通過設(shè)置 scrollDirection 參數(shù)來控制視圖的滾動方向。

我們通過下面的代碼實現(xiàn)一個水平滾動的內(nèi)容:

  • 這里需要注意,我們需要給Container設(shè)置width,否則它是沒有寬度的,就不能正常顯示。
  • 或者我們也可以給ListView設(shè)置一個itemExtent,該屬性會設(shè)置滾動方向上每個item所占據(jù)的寬度。
class MyHomeBody extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return ListView(
      scrollDirection: Axis.horizontal,
      itemExtent: 200,
      children: <Widget>[
        Container(color: Colors.red, width: 200),
        Container(color: Colors.green, width: 200),
        Container(color: Colors.blue, width: 200),
        Container(color: Colors.purple, width: 200),
        Container(color: Colors.orange, width: 200),
      ],
    );
  }
}

1.2. ListView.build

通過構(gòu)造函數(shù)中的children傳入所有的子Widget有一個問題:默認會創(chuàng)建出所有的子Widget。

但是對于用戶來說,一次性構(gòu)建出所有的Widget并不會有什么差異,但是對于我們的程序來說會產(chǎn)生性能問題,而且會增加首屏的渲染時間。

我們可以ListView.build來構(gòu)建子Widget,提供性能。

1.2.1. ListView.build基本使用

ListView.build適用于子Widget比較多的場景,該構(gòu)造函數(shù)將創(chuàng)建子Widget交給了一個抽象的方法,交給ListView進行管理,ListView會在真正需要的時候去創(chuàng)建子Widget,而不是一開始就全部初始化好。

該方法有兩個重要參數(shù):

  • itemBuilder:列表項創(chuàng)建的方法。當列表滾動到對應(yīng)位置的時候,ListView會自動調(diào)用該方法來創(chuàng)建對應(yīng)的子Widget。類型是IndexedWidgetBuilder,是一個函數(shù)類型。
  • itemCount:表示列表項的數(shù)量,如果為空,則表示ListView為無限列表。

我們還是通過一個簡單的案例來認識它:

class MyHomeBody extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      itemCount: 100,
      itemExtent: 80,
      itemBuilder: (BuildContext context, int index) {
        return ListTile(title: Text("標題$index"), subtitle: Text("詳情內(nèi)容$index"));
      }
    );
  }
}

1.2.2. ListView.build動態(tài)數(shù)據(jù)

在之前,我們搞了一個yz.json數(shù)據(jù),我們現(xiàn)在動態(tài)的來通過JSON數(shù)據(jù)展示一個列表。

思考:這個時候是否依然可以使用StatelessWidget:

答案:不可以,因為當前我們的數(shù)據(jù)是異步加載的,剛開始界面并不會展示數(shù)據(jù)(沒有數(shù)據(jù)),后面從JSON中加載出來數(shù)據(jù)(有數(shù)據(jù))后,再次展示加載的數(shù)據(jù)。

  • 這里是有狀態(tài)的變化的,從無數(shù)據(jù),到有數(shù)據(jù)的變化。
  • 這個時候,我們需要使用StatefulWidget來管理組件。

展示代碼如下:

import 'model/anchor.dart';

...省略中間代碼
class MyHomeBody extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return MyHomeBodyState();
  }
}

class MyHomeBodyState extends State<MyHomeBody> {
  List<Anchor> anchors = [];

  // 在初始化狀態(tài)的方法中加載數(shù)據(jù)
  @override
  void initState() {
    getAnchors().then((anchors) {
      setState(() {
        this.anchors = anchors;
      });
    });

    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      itemBuilder: (BuildContext context, int index) {
        return Padding(
          padding: EdgeInsets.all(8),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: <Widget>[
              Image.network(
                anchors[index].imageUrl,
                fit: BoxFit.fitWidth,
                width: MediaQuery.of(context).size.width,
              ),
              SizedBox(height: 8),
              Text(anchors[index].nickname, style: TextStyle(fontSize: 20),),
              SizedBox(height: 5),
              Text(anchors[index].roomName)
            ],
          ),
        );
      },
    );
  }
}

1.2.3. ListView.separated

ListView.separated可以生成列表項之間的分割器,它除了比ListView.builder多了一個separatorBuilder參數(shù),該參數(shù)是一個分割器生成器。

下面我們看一個例子:奇數(shù)行添加一條藍色下劃線,偶數(shù)行添加一條紅色下劃線:

class MySeparatedDemo extends StatelessWidget {
  Divider blueColor = Divider(color: Colors.blue);
  Divider redColor = Divider(color: Colors.red);

  @override
  Widget build(BuildContext context) {
    return ListView.separated(
      itemBuilder: (BuildContext context, int index) {
        return ListTile(
          leading: Icon(Icons.people),
          title: Text("聯(lián)系人${index+1}"),
          subtitle: Text("聯(lián)系人電話${index+1}"),
        );
      },
      separatorBuilder: (BuildContext context, int index) {
        return index % 2 == 0 ? redColor : blueColor;
      },
      itemCount: 100
    );
  }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容