1. 程式人生 > >Flutter中打造多行列列表GridView元件的使用

Flutter中打造多行列列表GridView元件的使用

GridView元件。一個可滾動的二維空間陣列。

在使用無限載入滾動列表的時候,最先使用的還是ListView元件。但若是要一行顯示2列或者更多列的滾動列表,GridView元件更為方便。如下

在向伺服器請求資料後,伺服器往往會返回一段json字串。而我們要想更加靈活的使用資料的話需要把json字串轉化成物件。由於flutter只提供了json to Map。而手寫反序列化在大型專案中極不穩定,很容易導致解析失敗。所有最好使用json_serializable 自動反序列化。

首先在pubspec.yaml檔案中dependencies新增json_annotation,dev_dependencies新增json_serializable

dependencies:
  flutter:
    sdk: flutter

  # The following adds the Cupertino Icons font to your application.
  # Use with the CupertinoIcons class for iOS style icons.
  cupertino_icons: ^0.1.2
  json_annotation: ^2.0.0
  cached_network_image: ^0.5.1
  transparent_image: ^0.1.0
  dio: ^1.0.9
  video_player: 
^0.7.2 flutter_spinkit: ^2.1.0 dev_dependencies: build_runner: ^1.0.0 json_serializable: ^2.0.0 flutter_test: sdk: flutter

 

以json_serializable的方式建立model類

建立一個模型picmodel.dart

import 'package:json_annotation/json_annotation.dart';
part 'picmodel.g.dart';

@JsonSerializable()
class PicModel {
  PicModel(
this.createdAt,this.publishedAt,this.type,this.url); String createdAt; String publishedAt; String type; String url; factory PicModel.fromJson(Map<String,dynamic> json) => _$PicModelFromJson(json); }

 

此時這個picmodel.g.dart檔案是不存在的,必須執行程式碼生成器來為我們生成序列化模板。通過在我們的專案根目錄下執行flutter packages pub run build_runner build,我們可以在需要時為我們的model生成json序列化程式碼。 這觸發了一次性構建,它通過我們的原始檔,挑選相關的併為它們生成必要的序列化程式碼。

然後建立find.dart檔案,搭建基礎構架。引入相關的庫

import 'package:flutter/material.dart';
import 'dart:io';
import 'dart:convert';
import 'package:flutter_yuan/models/picmodel.dart';
import 'package:cached_network_image/cached_network_image.dart';

class FindPage extends StatefulWidget{
  FindPage({Key key}):super(key:key);
  @override
  createState() => new _FindPageState();
}

class _FindPageState extends State<FindPage> {
  List<PicModel> picList = new List();
  int page = 1;
  @override
  void initState() {
    super.initState();
    _getPicList();
  }
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      
    );
  }
}

 

我們需要通過_getPicList來非同步請求資料:

_getPicList() async{
    String url = 'https://www.apiopen.top/meituApi?page=$page';
    var httpClient = new HttpClient();
    try {
      var req = await httpClient.getUrl(Uri.parse(url));
      var res = await req.close();
      // print(res);
      if(res.statusCode == HttpStatus.OK) {
        var jsonString = await res.transform(utf8.decoder).join();//將結果轉換成字串拼接
        // print(jsonString);
        Map data = jsonDecode(jsonString);//格式化成Map物件
        print(data);
        List pics = data['data'];
        List<PicModel> items = new List();
        for (var value in pics) {
          items.add(new PicModel.fromJson(value));
        };
        setState(() {         this.picList.addAll(items);          
          this.page ++;
        });
      }
    } catch (e) {
      
    }
  }

 

然後構建Widget:

Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('美圖'),
        centerTitle: true,
      ),
      body: new GridView.builder(
        padding: const EdgeInsets.all(10.0),
        gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
          crossAxisCount: 3,
          mainAxisSpacing: 10.0,
          crossAxisSpacing: 10.0,
        ),
        itemCount: picList.length,
        itemBuilder: (BuildContext context, int index) {
          if(index == picList.length - 1 ){
            _getPicList();
          }
          return buildItem(picList[index]);
        },
      ),
    );
  }

 

使用GridView.builder元件來構建列表,通過gridDelegate屬性來對列表樣式進行豐富。crossAxisCount屬性可以設定每行的列數,打造你的瀑布流佈局。

buidItem方法對圖片的樣式佈局。

buildItem(item) {
    return new GestureDetector(
      onTap: () {
        Navigator.push(
          context, 
          new MaterialPageRoute(
            builder: (context) => 
            new Scaffold(
              appBar: new AppBar(
                title: new Text('圖片詳情'),
              ),
              body: new Center(
                child: new Container(
                  width: 300.0,
                  child: new CachedNetworkImage(
                    imageUrl: item.url,
                    fit: BoxFit.fitWidth,
                  ),
                )
              ),
            )
          )
        );
      },
      child: new CachedNetworkImage(
        errorWidget: new Icon(Icons.error),
        imageUrl: item.url,
        fadeInDuration: new Duration(seconds: 3),
        fadeOutDuration: new Duration(seconds: 1),
      ),
    );
  }