1. 程式人生 > >Flutter使用ListView載入列表資料

Flutter使用ListView載入列表資料

移動端UI展示最常見的展示形式莫過於列表,Android中使用ListView/Recyclerview,iOS也有UIListView,都可以實現列表展示。Flutter作為相容Android和iOS的移動UI框架,自然也有實現此功能的元件,即ListView。

本文資料採用爬蟲爬取華爾街見聞全球資訊,然後採用GraphQL介面請求資料。顯示效果如下
在這裡插入圖片描述

實現

  • 建立ListView 及每個顯示的item
  • 網路請求
  • json解析
  • 資料顯示

建立ListView及每個顯示的item

使用如下程式碼建立一個ListView
其中listData 為列表載入的資料,因先初始化下 List listData = [];

      ListView getListView() => new ListView.builder(
      itemCount: (listData== null) ? 0 : listData.length,
      itemBuilder: (BuildContext context, int position) {
        return getItem(position);
      });

上面的getItem方法即為列表item的佈局,使用Column與Row實現垂直和水平佈局,核心程式碼如下:

new Padding(
            padding: new EdgeInsets.fromLTRB(10.0, 0.0, 10.0, 0.0),
            child: new Column(
              children: <Widget>[
                new Row(
                  crossAxisAlignment: CrossAxisAlignment.start, //縱向對齊方式:起始邊對齊
                  mainAxisSize: MainAxisSize.max,
                  children: <Widget>[
                    new Expanded(
                      child: Container(
                        height: 95.0,
                        child: getImage(data.articleThumbnail),//封面
                        alignment: FractionalOffset.center,
                      ),
                      flex: 1,
                    ),
                    new Expanded(
                      child: Container(
                        height: 95.0,
                        margin: new EdgeInsets.fromLTRB(5.0, 0.0, 0.0, 0.0),
                        child: new Column(
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: <Widget>[
                            new Container(
                              child: new Text(
                                articleTitle,//標題
                                style: new TextStyle(
                                    fontSize: 20.0,
                                    fontWeight: FontWeight.w700),
                                maxLines: 1,
                                overflow: TextOverflow.ellipsis,
                              ),
                              alignment: FractionalOffset.topLeft,
                            ),
                            new Container(
                              child: new Text("${data.articleBrief}",//概要
                                  style: new TextStyle(fontSize: 16.0),
                                  maxLines: 2,
                                  overflow: TextOverflow.ellipsis),
                              alignment: Alignment.topLeft,
                            ),
                            new Expanded(
                              child: new Container(
                                margin:
                                    new EdgeInsets.fromLTRB(0.0, 5.0, 0.0, 0.0),
                                child: new Stack(
                                  children: <Widget>[
                                    new Container(
                                      child: new Text("${data.articleAuthor}",
                                          style: new TextStyle(fontSize: 10.0)),//作者
                                      alignment: FractionalOffset.bottomLeft,
                                    ),
                                    new Container(
                                      child: new Text(time_str,
                                          style: new TextStyle(fontSize: 10.0)),//時間
                                      alignment: FractionalOffset.bottomRight,
                                    ),
                                  ],
                                ),
                              ),
                            )
                          ],
                        ),
                      ),
                      flex: 3,
                    ),
                  ],
                ),
                new Divider(), //分割線
              ],
            ),
          )


  /**
   * 列表中圖片載入
   */
  getImage(String img_url) {
    return new CachedNetworkImage(
      imageUrl: img_url,
      errorWidget: new Icon(Icons.error),
      fit: BoxFit.cover,
      height: 85.0,
      width: 100.0,
    );
  }

上述程式碼對應顯示效果如下:
在這裡插入圖片描述
程式碼中CachedNetworkImage為網路圖片快取元件cached_network_image載入。

網路請求

網路請求使用的是開源的Dio,也可以直接使用http傳送請求,

    Dio dio = new Dio();
    Response response = await dio.get(url);
    var jsonString = response.data;

json解析

json_serializable這個可以對json做很好的解析,類似於安卓的Gson,具體使用可以參考這篇文章,博主也是按文章進行操作的。

try {
      var news = new news_enity.fromJson(jsonString);
      var code = news.code;
      if (code == 0) {
        Result result = news.result;
        datas = result.data;
      }
    } catch (e) {
      print("異常==》" + e.toString());
    }

資料顯示

使用 setState,將請求獲得的資料datas傳遞給ListView的資料來源listData

    setState(() {
      listData= datas;
    });

但列表顯示肯定是要等到下網路請求到時間後才能顯示的,所以有段時間我們需要用精度條轉圈來顯示等待,沒有資料時,載入loading進度條,有資料後立馬顯示列表

  getBody() {
  if (listData.isEmpty) {
      return getProgressDialog();
    } else {
      return new Container(
        padding: new EdgeInsets.fromLTRB(0.0, 10.0, 0.0, 10.0),
        child: getListView(),
      );
    }
  }
  
  getProgressDialog() {
  // // CircularProgressIndicator是一個圓形的Loading進度條
    return new Center(child: new CircularProgressIndicator());
  }

最後效果如下圖
在這裡插入圖片描述

專案原始碼地址,此專案為持續開發專案,歡迎Start和Fork