Flutter小知識-- widget初窺

Android當中,一切都是View。佈局類View稱爲ViewGroup。Flutter當中,一切都是Widget。
而根據Widget是否須要包含子節點將Widget分爲了三類:數組

  • 沒有子節點的widget
  • 只有一個孩子的widget
  • 包含多個孩子的widget

而咱們在前文中也提到過,Element樹纔是最終的繪製樹,Element樹是經過widget樹來建立的(經過Widget.createElement()),widget其實就是Element的配置數據。
Flutter中,根據Widget是否須要包含子節點將Widget分爲了三類,分別對應三種Element,以下表:bash

Widget 對應的Element 用途
LeafRenderObjectWidget LeafRenderObjectElement Widget樹的葉子節點,用於沒有子節點的widget,一般基礎widget都屬於這一類,如Text、Image。
SingleChildRenderObjectWidget SingleChildRenderObjectElement 包含一個子Widget,如:ConstrainedBox、DecoratedBox等
MultiChildRenderObjectWidget MultiChildRenderObjectElement 包含多個子Widget,通常都有一個children參數,接受一個Widget數組。如Row、Column、Stack等

注意,Flutter中的不少Widget是直接繼承自StatelessWidget或StatefulWidget,而後在build()方法中構建真正的RenderObjectWidget,如Text,它實際上是繼承自StatelessWidget,而後在build()方法中經過RichText來構建其子樹,而RichText纔是繼承自LeafRenderObjectWidget。因此爲了方便敘述,咱們也能夠直接說Text屬於LeafRenderObjectWidget(其它widget也能夠這麼描述),這纔是本質。讀到這裏咱們也會發現,其實StatelessWidget和StatefulWidget就是兩個用於組合Widget的基類,它們自己並不關聯最終的渲染對象(RenderObjectWidget)。less

基礎Widget簡介

與原生開發中「控件」不一樣的是,Flutter中的widget的概念更普遍,它不只能夠表示UI元素,也能夠表示一些功能性的組件如:用於手勢檢測的 GestureDetector widget、用於應用主題數據傳遞的Theme等等。
這裏特指直接呈現UI的widget,好比文本、按鈕、圖片、Icon、輸入框表單等等。
好比,Material widget庫中提供了多種按鈕Widget如RaisedButton、FlatButton。全部Material 庫中的按鈕都有以下相同點:佈局

  1. 按下時都會有「水波動畫」。
  2. 有一個onPressed屬性來設置點擊回調,當按鈕按下時會執行該回調,若是不提供該回調則按鈕會處於禁用狀態,禁用狀態不響應用戶點擊。
RaisedButton(
  child: Text("normal"),
  onPressed: () => {},
),
FlatButton(
  child: Text("normal"),
  onPressed: () => {},
),
OutlineButton(
  child: Text("normal"),
  onPressed: () => {},
),
IconButton(
  icon: Icon(Icons.send),
  onPressed: () => {},
),
FlatButton(
  child: Text("Submit"),
  color: Colors.blue,
  highlightColor: Colors.blue[700],
  colorBrightness: Brightness.dark,
  textColor: Colors.white,
  padding: EdgeInsets.all(10),
  shape: RoundedRectangleBorder(
      borderRadius : BorderRadius.circular(20)
  ),
  splashColor: Colors.grey,
  onPressed: (){},
),
複製代碼

對應的效果以下: 動畫

Widget基礎

佈局類Widget

直接或間接繼承(包含)MultiChildRenderObjectWidget的Widget,它們通常都會有一個children屬性用於接收子Widget。 好比 線性佈局Row和Column、彈性佈局Flex、流式佈局Wrap、Flow、層疊佈局Stack、Positioned等。 這裏以Wrap舉例。Flutter中,子widget超出屏幕範圍,則會報溢出錯誤。
ui

overflow

能夠看到,右邊溢出部分報錯。這是由於Row默認只有一行,若是超出屏幕不會折行。咱們把超出屏幕顯示範圍會自動折行的佈局稱爲流式佈局。Flutter中經過Wrap和Flow來支持流式佈局,將上例中的Row換成Wrap後溢出部分則會自動折行。下面是Wrap的定義:

Wrap({
  ...
  this.direction = Axis.horizontal,
  this.alignment = WrapAlignment.start,
  this.spacing = 0.0,
  this.runAlignment = WrapAlignment.start,
  this.runSpacing = 0.0,
  this.crossAxisAlignment = WrapCrossAlignment.start,
  this.textDirection,
  this.verticalDirection = VerticalDirection.down,
  List<Widget> children = const <Widget>[],
})
複製代碼

樣例代碼以下:this

Wrap(
  spacing: 8.0, // 主軸(水平)方向間距
  runSpacing: 4.0, // 縱軸(垂直)方向間距
  alignment: WrapAlignment.center, //沿主軸方向居中
  children: <Widget>[
    new Chip(
      avatar: new CircleAvatar(backgroundColor: Colors.blue, child: Text('A')),
      label: new Text('Hamilton'),
    ),
    new Chip(
      avatar: new CircleAvatar(backgroundColor: Colors.blue, child: Text('M')),
      label: new Text('Lafayette'),
    ),
    new Chip(
      avatar: new CircleAvatar(backgroundColor: Colors.blue, child: Text('H')),
      label: new Text('Mulligan'),
    ),
    new Chip(
      avatar: new CircleAvatar(backgroundColor: Colors.blue, child: Text('J')),
      label: new Text('Laurens'),
    ),
  ],
)
複製代碼

效果以下圖: spa

wrap

容器類Widget

直接或間接繼承(包含)SingleChildRenderObjectWidget的Widget,它們通常都會有一個child屬性用於接收子Widget。 這一類的widget有Padding、ConstrainedBox、DecoratedBox等。3d

容器類Widget和佈局類Widget都做用於其子Widget,不一樣的是:code

  • 佈局類Widget通常都須要接收一個widget數組(children),他們直接或間接繼承自(或包含)MultiChildRenderObjectWidget.
    佈局類Widget是按照必定的排列方式來對其子Widget進行排列;

  • 容器類Widget通常只須要接收一個子Widget(child),他們直接或間接繼承自(或包含)SingleChildRenderObjectWidget。
    容器類Widget通常只是包裝其子Widget,對其添加一些修飾(補白或背景色等)、變換(旋轉或剪裁等)、或限制(大小等)。

更多widget瞭解能夠跳轉這裏


若是你以爲這篇文章對你有益,還請幫忙轉發和點贊,萬分感謝。

Flutter爛筆頭
相關文章
相關標籤/搜索