Flutter 開發從 0 到 1(三)佈局與 ListView

吳小龍同學發表於2020-10-08

上週日出去玩了,因此沒時間寫文章。我司加班到 11 點,第二天可以晚上班一個小時,加班到 12 點,可以晚上班兩個小時,以此類推,為什麼說這個,對的,加班第二天我沒有多睡覺,而是起來抓緊時間寫文章,好了,廢話不多說,進入今天的主題。

佈局

說到 Android 佈局,不是很難,會在對應的 xml 里布局,Flutter 裡沒有 xml,都在程式碼裡寫,給人感覺就很難,看下我們要實現的佈局:

開啟 PhotoShop,看下背景色 #ededed,日期字型顏色 #a6a6a6,標題字型顏色 #1b1b1b,摘要字型顏色 #808080。

公眾號這是列表,我先將 item 搞定。看這佈局都是線性佈局,這要在之前,分分鐘搞定,但 Flutter……好吧,Flutter 佈局可沒那麼簡單,我花了好幾個小時才做好,期間遇到了不少困難。

Flutter 也有橫向 Row 佈局和豎向 Column 佈局,我本想分 1 和 2 兩個部分,最外層豎向 Column 包含 1 和 2,2 本身是 Column,包含一個 image 和兩個 text,直接使用 Column 可以完成,當我需要設定 2 裡面白色的背景色,發現 Column 根本沒有背景色屬性,於是把 2 最外層改造成 Container。

使用 Container 沒有問題,佈局也很快實現了,接下來是實現四角的圓角效果。

Container 有 decoration,可以實現圓角,我遇到了兩個問題:

1、當 shape: BoxShape.circle 時不能設定 borderRadius ,會異常
異常資訊:'shape != BoxShape.circle ||borderRadius == null': is not true.

2、使用 BoxDecoration
Container 不能使用 color,會報錯:
Cannot provide both a color and a decoration
To provide both, use "decoration: BoxDecoration(color: color)".

以為這樣就實現了圓角,不,不會那麼順利的,發現圖片根本沒有圓角效果,這和之前 Java 實現方式不一樣,最外層都實現了圓角,對裡面的佈局(圖片)居然沒有生效,最後只好把佈局實現如下:

分成 1、2、3 部分,3 還是 Container,2 和 3 圓角效果只對上下部分分別實現,完整程式碼如下:

blogItem() {
    var date = new Padding(
        padding: const EdgeInsets.only(
          top: 20.0,
          left: 10.0,
          right: 10.0,
        ),
        child: new Text(
          '2020年6月28日 22:49',
          textAlign: TextAlign.center,
          style: TextStyle(color: ColorCommon.dateColor, fontSize: 18),
        ));

    var cover = new Padding(
        padding: const EdgeInsets.only(
          top: 10.0,
          left: 10.0,
          right: 10.0,
        ),
        child: new ClipRRect(
            borderRadius: BorderRadius.only(
                topLeft: Radius.circular(10.0),
                topRight: Radius.circular(10.0)),
            child: new Image.network(
              'http://pic1.win4000.com/wallpaper/2020-04-21/5e9e676001e20.jpg',
            )));

    var title = new Text(
      'APP 開發從 0 到 1(一)需求與準備',
      style: TextStyle(color: ColorCommon.titleColor, fontSize: 22),
    );

    var summary = new Padding(
        padding: const EdgeInsets.only(
          top: 5.0,
        ),
        child: new Text('一個人做一個專案,你也可以。',
            textAlign: TextAlign.left,
            style: TextStyle(color: ColorCommon.summaryColor, fontSize: 18)));

    var titleSummary = new Container(
      padding: const EdgeInsets.all(10.0),
      alignment: Alignment.topLeft,
      decoration: new BoxDecoration(
        color: Colors.white,
        borderRadius: BorderRadius.only(
            bottomLeft: Radius.circular(10.0),
            bottomRight: Radius.circular(10.0)),
        shape: BoxShape.rectangle,
      ),
      margin: const EdgeInsets.only(left: 10, right: 10.0),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        mainAxisSize: MainAxisSize.min,
        children: <Widget>[title, summary],
      ),
    );

    var blogItem = new Column(
      children: <Widget>[date, cover, titleSummary, date, cover, titleSummary],
    );

    return blogItem;
  }

實際效果如下:

好了,關於 Flutter 佈局就講到這裡,我只是針對這個專案所需要的去實現,Flutter 佈局的東西還有很多,其屬性讓人眼花撩亂,可以去官網一個個去仔細學習和實踐。

ListView

blogItem 寫好了,完成了大頭,接下來就要填充真實的資料,在《APP 開發從 0 到 1(二)框架與網路》,有說到網路請求,其中有提到 setstate(){} 方法,呼叫這個方法會回撥 build 方法,這樣我們可以在 build 方法加個判斷,先載入 Progress,待網路資料請求完,再顯示 ListView,程式碼如下:

@override
  Widget build(BuildContext context) {
    var content;
    if (blogList.isEmpty) {
      content = new Center(
        // 可選引數 child:
        child: new CircularProgressIndicator(),
      );
    } else {
      content = new ListView(children: blogItem());
    }

    return Scaffold(
      backgroundColor: ColorCommon.backgroundColor,
      appBar: AppBar(
        title: Text('AndBlog'),
      ),
      body: content,
      floatingActionButton: FloatingActionButton(
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }

blogItem() {
    List<Widget> widgets = [];
    for (int i = 0; i < blogList.length; i++) {
      Blog blog = blogList[i];
      var date = new Padding(
          padding: const EdgeInsets.only(
            top: 20.0,
            left: 10.0,
            right: 10.0,
          ),
          child: new Text(
            // 填充真實資料
            blog.date,
            textAlign: TextAlign.center,
            style: TextStyle(color: ColorCommon.dateColor, fontSize: 18),
          ));

      //……

      var blogItem = new Column(
        children: <Widget>[
          date,
          cover,
          titleSummary,
        ],
      );
      widgets.add(blogItem);
    }
    return widgets;
  }

這樣 ListView 也完成了,接下來需要完成的是 ListView 載入更多。

相關文章