flutter筆記7:flutter頁面佈局基礎,看完這篇就可以用flutter寫APP了

燃燒的魚丸發表於2018-03-13

不知不覺已經到了第7篇,然而很多萌新玩家可能還是不知道如何堆砌控制元件,像用CSS一樣搭出漂亮的APP介面,我也一樣,紅紅火火恍恍惚惚,直到今天含淚讀完Flutter佈局基礎,彷彿開啟了一個全新的世界。

##基本概念

在flutter中,**一切皆控制元件!一切皆控制元件!一切皆控制元件!**牢牢記住這個概念。Text是控制元件,Image是控制元件,Icon是控制元件,佈局腳手架也Scaffold也是控制元件,甚至整個APP也是控制元件。

使用者自定義控制元件分為有狀態控制元件和無狀態控制元件兩種型別,其特性在前面的筆記4中可以感受感受。

flutter的內建控制元件分為兩種:

  • 可視控制元件(visible widget)。即我們直接看到的控制元件,如text、Icon、Button,名稱理解和html標籤相同。
  • 佈局控制元件(layout widget)。可以理解為架子,如Row、Column、Container。佈局控制元件不會直接呈現內容,可看作承載可視控制元件的容器。所有的佈局控制元件都有承載子控制元件的屬性:childchildrenchild可承載單個子控制元件,children可承載多個子控制元件。每個佈局控制元件有預設的佈局方式,使其子控制元件按照自己的樣式安放到位子上。佈局控制元件提供了各種樣式的引數,可實現子控制元件的對齊(align)、縮放(size)、包裝(pack)和巢狀(Nest)。簡單總結為:佈局控制元件是為了實現可視控制元件的各種視覺效果而做的包裝,比如前端的html為了實現sticky、雙飛翼、聖盃等佈局常常內容區外層新增div包裹層。

佈局控制元件也是可以模擬顯示的,通常用於除錯佈局樣式時用到的網格線、標尺、動畫幀等。啟用方式: 1.在main.dart中,引入包:

import 'package:flutter/rendering.dart' show debugPaintSizeEnabled;
複製程式碼

2.在main函式中開啟開關:

void main() {
  debugPaintSizeEnabled = true;      //開啟視覺除錯開關
  runApp(new MyApp());
}
複製程式碼

執行程式碼後APP效果如下:

視覺除錯模式下的APP介面

flutter的內建控制元件已經定義了很多屬性,玩家可以參考Widgets Catalog瞭解每種控制元件的詳細屬性和用法。本篇通過幾個例子,介紹頁面上的控制元件如何堆砌和佈局。

彆著急,由於下面的案例中,可能用到圖片,先交待一下載入圖片的基本配置方法:

  1. 到專案根目錄下建立一個資料夾,命名:images,將圖片放置到該資料夾中。

  2. 開啟根目錄下的pubspec.yaml檔案,在其下新增註釋中的屬性:

    flutter: uses-material-design: true assets: //如果沒有這個屬性則新增到flutter標籤下 - images/lake.jpg //宣告圖片的路徑

  3. 到程式碼中,以image控制元件的方式引用圖片:

    new Image.asset( 'images/lake.jpg', //圖片的路徑 width: 600.0, //圖片控制元件的寬度 height: 240.0, //圖片控制元件的高度 fit: BoxFit.cover, //告訴引用圖片的控制元件,影象應儘可能小,但覆蓋整個控制元件。 ),

##案例

####控制元件的排列 行(Row)和列(Column),是flutter中最常用的兩個佈局控制元件,他們只能容納當前螢幕尺寸大小的內容,如果其內部的子控制元件超出螢幕尺寸,不但不會自動生成滾動條,還會報錯。

案例1-行排列

橫向排列

如圖上圖所示,圖中有3個100px寬的圖片,通過水平平均間隔的方式居中橫向排列顯示到一行中,程式碼示例:

 new Center(                //居中控制元件
  child: new Row(        //行控制元件
    mainAxisAlignment: MainAxisAlignment.spaceEvenly,      //對齊方式:平均間隔
    children: [
      new Image.asset('images/pic1.jpg'),        //引入三張圖片
      new Image.asset('images/pic2.jpg'),
      new Image.asset('images/pic3.jpg'),
    ]
  )
)
複製程式碼

可以看到上圖用到了2個佈局控制元件Center和Row,通過Center包裹Row,使行控制元件保持居中,而ROW控制元件包裹了3個圖片控制元件Image,通過配置Row的mainAxisAlignment對齊屬性,使三個圖片空間通過平均間隔的方式進行橫向排列。

完整程式碼: Dart code:main.dart Images:images Pubspec:pubspec.yaml

案例2-列排列

縱向排列

如上圖所示,還是那3張圖,通過縱向平均間隔的方式顯示到一列中,程式碼如下:

new Center(
  child: new Column(
    mainAxisAlignment: MainAxisAlignment.spaceEvenly,        //對齊方式:平均間隔
    children: [
      new Image.asset('images/pic1.jpg'),
      new Image.asset('images/pic2.jpg'),
      new Image.asset('images/pic3.jpg'),
    ]
  )
)
複製程式碼

完整程式碼: Dart code:main.dart Images:images Pubspec:pubspec.yaml

對比案例1和2可以看到,程式碼結構相同,Row和Column中都用到了mainAxisAlignment屬性,除此以外還有crossAxisAlignment屬性。值得注意的是,在Row中mainAxisAlignment控制水平方向對齊,crossAxisAlignment控制垂直方向對齊,而在Column中則正好相反。相關引數值請參考MainAxisAlignmentCrossAxisAlignment

####佈局控制元件的巢狀 案例3-行列巢狀

行列巢狀

如上圖,我們將圖中的元素按圖中的框線進行分解:

1.最外層的使用Row控制元件包裹,使其內部的兩個子控制元件:淺藍色框的菜品介紹和右邊的菜品大圖橫向排列,程式碼如下:

new Scaffold(                                                                              //腳手架控制元件
      appBar: new AppBar(                                                            //工具欄控制元件
        title: new Text(widget.title),
      ),
  body: new Center(
  child: new Container(                                                                 //Container控制元件用於調整外邊距
    margin: new EdgeInsets.fromLTRB(0.0, 40.0, 0.0, 30.0),        
    height: 600.0,
    child: new Card(                                                                       //Card控制元件控制卡片的視覺效果
      child: new Row(                                                                     //Row控制元件使其子控制元件橫向排列
        crossAxisAlignment: CrossAxisAlignment.start,                  //縱向對齊方式:起始邊對齊
        children: [
          new Container(                                                                  //Container控制元件用於調整寬度
            width: 440.0,   
            child: leftColumn,                                                            //左邊的菜品介紹控制元件
          ),
          mainImage,                                                                        //右邊的大圖控制元件
        ],
      ),
    ),
  ),
)
)
複製程式碼

2.把淺藍色框內的資訊,用Column包裹,使其內容垂直排列:

new Container(
      padding: new EdgeInsets.fromLTRB(20.0, 30.0, 20.0, 20.0),
      child: new Column(                                                                    //Column控制元件,使其子控制元件垂直排列
        children: [
          titleText,        //標題行,包含了可視Text控制元件
          subTitle,        //副標題行,包含了可視Text控制元件
          ratings,         //投票資訊行
          iconList,        //小圖示行
        ],
      ),
    );
複製程式碼

3.由於titleText和subTitle都是簡單的包裝了Text控制元件,不再貼程式碼和註釋,重點講下ratings和iconList:

ratings和iconList控制元件

ratings和iconList控制元件是垂直排列的兩行,而各自內部有自己的佈局資訊,因此將這兩行分別拆解為:

ratings

ratings下包含了兩個水平排列:Row控制元件用於顯示星級,Text控制元件用於顯示使用者瀏覽數。而評分星級控制元件ROW又分解為5個水平排列的Icon控制元件。

iconList控制元件結構

iconList橫向排列了3個縱向顯示的控制元件,層次一目瞭然。

對照程式碼結構:

//ratings控制元件
new Container(
      padding: new EdgeInsets.all(20.0),
      child: new Row(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: [
          new Row(
            mainAxisSize: MainAxisSize.min,       //mainAxisSize,可壓縮或伸長行內控制元件的間距
            children: [
              new Icon(Icons.star, color: Colors.black),
              new Icon(Icons.star, color: Colors.black),
              new Icon(Icons.star, color: Colors.black),
              new Icon(Icons.star, color: Colors.black),
              new Icon(Icons.star, color: Colors.black),
            ],
          ),
          new Text(
            '170 Reviews',
            style: new TextStyle(
              color: Colors.black,
              fontWeight: FontWeight.w800,
              fontFamily: 'Roboto',
              letterSpacing: 0.5,
              fontSize: 20.0,
            ),
          ),
        ],
      ),
    )

//iconList控制元件
new Container(
        padding: new EdgeInsets.all(20.0),
        child: new Row(
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: [
            new Column(
              children: [
                new Icon(Icons.kitchen, color: Colors.green[500]),
                new Text('PREP:'),
                new Text('25 min'),
              ],
            ),
            new Column(
              children: [
                new Icon(Icons.timer, color: Colors.green[500]),
                new Text('COOK:'),
                new Text('1 hr'),
              ],
            ),
            new Column(
              children: [
                new Icon(Icons.restaurant, color: Colors.green[500]),
                new Text('FEEDS:'),
                new Text('4-6'),
              ],
            ),
          ],
        ),
      )
複製程式碼

Row和Column可以相互包裹,使頁面能夠實現整齊的佈局,只因其特性總是橫向或縱向充滿父控制元件,比如最外層使用時,會自動充滿全螢幕。但是當頁面內容需要超出螢幕尺寸時,就用ListTileListView代替。

最終顯示效果

完整程式碼(由於手機螢幕尺寸無法適應此案例,執行後長和寬都會報溢位錯誤,大家最好使用平板虛擬機器測試此案例,或者調整程式碼中的字型大小和控制元件尺寸,以滿足顯示要求): Dart code:main.dart Images:images Pubspec:pubspec.yaml

####控制元件的縮放 案例4-縮放

子控制元件縮放

上圖中,三個橫向排列的圖片控制元件,中間控制元件的尺寸比兩邊的大一倍,程式碼如下:

new Center(
  child: new Row(
    crossAxisAlignment: CrossAxisAlignment.center,
    children: [
      new Expanded(
        child: new Image.asset('images/pic1.jpg'),
      ),
      new Expanded(              //使用Expanded控制元件對Image控制元件進行包裹
        flex: 2,                 //flex值預設為1,這裡改成2之後,其子控制元件2倍放大
        child: new Image.asset('images/pic2.jpg'),
      ),
     new Expanded(
        child: new Image.asset('images/pic3.jpg'),
      ),
))
複製程式碼

完整程式碼: Dart code:main.dart Images:images Pubspec:pubspec.yaml

由於處理邏輯和佈局樣式都一起書寫到程式碼中,加上控制元件的巢狀,flutter的程式碼會如同html的標籤一樣巢狀很多層,對前端開發者可能需要時間適應,但對我這種新萌來說降低了從CSS和處理程式碼之間來回對照的麻煩,並且flutter的內建控制元件預設的樣式已經十分整潔,無需單獨再學習類似前端CSS處理頁面佈局的語法和結構,總體來說降低了不少學習成本,上手更快更簡單。能在短時間內掌握生產技能,成就感油然而生,自然有繼續學下去的動力。

以上便是最基礎的排列布局介紹,相信看到這裡的小夥伴已經明白怎麼寫APP了,今天就到這裡~感謝大家支援! flutter 中文社群(官方QQ群:338252156)

相關文章