Flutter Widget 靜態佈局實戰

Aller_Dong發表於1970-01-01

前面兩篇文章介紹了 Flutter win環境的安裝,以及利用listview 實現了簡單佈局。(這篇文章篇幅有點長,讀完大概需要8.88分鐘)

Flutter 入門實現 ListView 列表頁面以及收藏頁面

Flutter 環境搭建以及填坑指南(Win10 系統且已有 Android 開發環境

這篇文章主要介紹以下內容:

1. ListView 能實現什麼效果?

2. widget 如何新增到 ListView 中?

3. ListView 點選事件,單個 widget 點選事件

4. ( 重點 ) widget 如何垂直、水平擺放?

5. 圖片、Icon、Text widget 的簡單使用

在這篇文章Flutter 入門實現 ListView 列表頁面以及收藏頁面中雖然實現了一個列表,但是怎麼實現的還沒仔細研究,現在就先從研究 ListView的實現開始吧。

先看一下之前實現的效果:

ListView 列表

實現的程式碼主要是RandomWordsState類中的下面程式碼:

return new ListTile(      // 單詞佈局      title: new Text(        pair.asPascalCase,        style: _biggerFont,      ),      // 喜歡小心心佈局      trailing: new Icon(        alreadySaved ? Icons.favorite : Icons.favorite_border,        color: alreadySaved ? Colors.red : null,      ),      // ListView item 的點選事件      onTap: () { 
// 通知框架狀態已經改變 setState(() {
if (alreadySaved) {
_saved.remove(pair);

} else {
_saved.add(pair);

}
});

}, );
複製程式碼

從上面的程式碼中可以看出實現這個列表主要就是操作了 ListTile 這個 Widget,那麼我們看看這個ListTile的構造方法都提供了上面功能吧!註釋都寫在程式碼中了~

/// Requires one of its ancestors to be a [Material] widget.  const ListTile({ 
Key key, // 在列表的左邊新增的 widget(如文末圖中的左邊圖片) this.leading, // 標題 this.title, // 副標題 this.subtitle, // 在列表的右邊新增的 widget(如文末圖中的右邊心形 icon) this.trailing, // 如果 isThreeLine 為 true, subtitle 則不能為 null,預設為 false // 如果 副標題為空則列表平鋪一行顯示,如果 副標題 不為空,則副標題所佔的佈局是兩行 // 如果 isThreeLine = true 則副標題可以顯示三行。 this.isThreeLine = false, // bool 型別,預設為false ,如果為 true 則 ListTile 在垂直方向是密集型擺放 //(具體效果待後面去實現,這裡只是看了註釋後的理解) this.dense, // 內容的邊距 this.contentPadding, // item 是否能點選 this.enabled = true, // item 的點選事件 this.onTap, // item 的長按事件 this.onLongPress, // item 是否選中標記 this.selected = false,
}) 複製程式碼

flutter 的開發語言是dart,這個語言之前沒學過,這裡就先不深入學習了,網上有比較好的這個博主 戀貓月亮寫的系列的文章寫的很好。我這裡就只寫實現上面圖片中展示的效果。

1. ListView 能實現什麼效果?

ListView 不僅可以實現列表佈局,還可以實現 Android 中的 ScrollView 的功能。關於 滾動的 widget 還有其他的實現,可參考**可滾動Widget簡介**

實現列表功能,如果是符合ListTile的樣式,直接使用ListTile實現很方便。(目前還沒學到如何實現多佈局,後面學習再寫一篇)

實現ScrollView功能,直接在build方法的body中新增我們的 widget。虛擬碼如下:

定義了一個DetailScreen詳情頁面,繼承了StatelessWidget,在build方法中返回了頁面的內容:appBar 是標題欄,body 是顯示的內容

class DetailScreen extends StatelessWidget { 
// Declare a field that holds the pair final WordPair pair;
// In the constructor, require a pair DetailScreen({Key key, @required this.pair
}) : super(key: key);
@override Widget build(BuildContext context) {
return new Scaffold( appBar: new AppBar( // 接收傳遞過來的單詞做標題名字 title: new Text("${pair.asPascalCase
}
"
), ), // 使用 ListView 做滾動列表 body: new ListView( children: [ // 顯示網路圖片 new Image.asset( 'images/wali.jpg', width: 600.0, height: 240.0, fit: BoxFit.cover, ), // 標題行(文末有實現效果) titleSection, // 按鈕行(文末有實現效果) buttonSection, // 描述文字(文末有實現效果) textSection, ], ), );

}
}複製程式碼

2. widget 如何新增到 ListView 中?

上面的虛擬碼中在構建一個有狀態的widget的時候會重寫 build方法,在該方法中的 body返回我們實現的 widget即可。

3. ListView 點選事件,單個 widget 點選事件

如果ListView使用ListTile實現列表的話,直接使用ListTile中的 onTap實現列表點選效果。如果不是用ListTile實現,那就使用單個widget的點選事件吧。

widget的如果有onTap方法可以直接呼叫該方法即可實現,如果沒有該方法,則需要使用GestureDetector來實現點選效果,例如上圖中的心形喜歡點選事件,虛擬碼實現如下:

關於GestureDetector可參考該文章 手勢識別GestureDetector

trailing: new GestureDetector(        // 心形喜歡 icon        child: new Icon(          alreadySaved ? Icons.favorite : Icons.favorite_border,          color: alreadySaved ? Colors.red : null,        ),        // 點選事件        onTap: (){ 
// 通知框架狀態已經改變 setState(() {
if (alreadySaved) {
_saved.remove(pair);

} else {
_saved.add(pair);

}
});

}, ),複製程式碼

4. widget 如何垂直、水平擺放?

最常見的佈局模式之一是垂直或水平排列widget。在Flutter可以使用行Row水平排列widget,並使用列Column垂直排列widget。 同時,每個孩子本身可以是一個Row或一個Column,依此類推。以下示例顯示如何在行或列內巢狀行或列。

通過下面兩張圖片可以學到在實現佈局時如何拆分:參考連結 widget 佈局

左側的一列和右側的圖片
左側的Column widget樹巢狀行和列

在控制行或列對齊其子項時使用mainAxisAlignment( 主軸 ) 和crossAxisAlignment( 橫軸 ) 屬性來。 對於行(Row)來說,**主軸是水平方向,橫軸垂直方向。**對於列(Column)來說,主軸垂直方向,橫軸水平方向。

Row
Column

MainAxisAlignmentCrossAxisAlignment 類提供了很多控制對齊的常量.MainAxisAlignment

  • center → const MainAxisAlignment :子 widget在主軸方向上居中顯示

  • end → const MainAxisAlignment :子 widget在主軸方向上居右邊顯示,如果是水平方向,那麼由 TextDirection 來決定end是在左邊(ltr)還是在右邊(rtl)。如果是豎直方向,那麼由 VerticalDirection 來決定end是在上邊(up)還是在下邊(down)

  • start → const MainAxisAlignment:子 widget在主軸方向上居左邊顯示,同理 end

  • spaceAround → const MainAxisAlignment:子widget中的第一個和最後一個widget距離邊的距離是它與中間的距離的一半。(這裡比較抽象,後期實現效果了會順帶講解)

  • spaceBetween → const MainAxisAlignment:子widget中的第一個和最後一個貼邊,剩餘的子widget將中間的空間平分。

  • spaceEvenly → const MainAxisAlignment:子widget 將佈局空間完全平分

    Row 方向完全平分
  • values → const List<
    <wbr>MainAxisAlignment>
    :根據值得大小來分配空間,值越大空間分配越多。

CrossAxisAlignment 屬性相同的基本和上面介紹的一樣,就不贅述了。

Expanded widget

Expanded widget,可以將widget的大小設定為適和行或列 Expanded有個屬性flex(彈性係數),預設情況下,每個widget的彈性係數為1,也就是會鋪滿布局。

例如實現:三張圖片水平鋪滿螢幕,即可使用Expanded包裹Image然後設定flex:1,不設定也行,因為預設flex就是1

效果圖

虛擬碼如下:

body: new Center(  child: new Row(    crossAxisAlignment: CrossAxisAlignment.center,    children: [      new Expanded(        child: new Image.asset('images/pic1.jpg'),      ),      new Expanded(        child: new Image.asset('images/pic2.jpg'),      ),      new Expanded(        child: new Image.asset('images/pic3.jpg'),      ),複製程式碼

聚集 widgets

預設情況下,行或列沿著其主軸會盡可能佔用儘可能多的空間,但如果要將孩子緊密聚集在一起,可以將mainAxisSize設定為MainAxisSize.min

例如實現:五個星形圖示圖示緊湊在一起。

效果圖

虛擬碼如下:

class _MyHomePageState extends State<
MyHomePage>
{
@override Widget build(BuildContext context) {
var packedRow = new Row( mainAxisSize: MainAxisSize.min, children: [ new Icon(Icons.star, color: Colors.green[500]), new Icon(Icons.star, color: Colors.green[500]), new Icon(Icons.star, color: Colors.green[500]), new Icon(Icons.star, color: Colors.black), new Icon(Icons.star, color: Colors.black), ], );
// ...
}複製程式碼

5. 圖片、Icon、Text widget 的簡單使用

這些都是基礎控制元件使用起來很簡單的,可檢視這個文件介紹:基礎 Widget

在學習完上面的內容我們可以實現出目前的樣式了:

flutter_1.gif

實現列表功能,以及一個可滾動的詳情頁面,頂部的標題是 listview 傳遞過去的單詞。

文章篇幅過長了,這裡就不介紹上圖的實現過程了,原始碼地址如下覺得還湊合的給個star,好讓我繼續堅持寫下去~原始碼地址

看原始碼或者上文中不理解的可以聯絡我,我會知無不言的。

本文完。

來源:https://juejin.im/post/5c4c6622f265da611d670162#comment

相關文章