iT邦幫忙

2023 iThome 鐵人賽

DAY 2
0

談到flutter第一個想到的一定是widget,我們在開發flutter app時90%的時間都是在撰寫widget,更明確的說應該是撰寫widget裡面的build method,我們也知道app啟動以後會按照我們寫進build裡的程式產生相應的畫面,但是到底framework是做了什麼事情才讓這一切都如此的理所當然的呢?

Widget

https://ithelp.ithome.com.tw/upload/images/20230917/20147150mVIoH2CtR7.png

首先先看看官方怎麼說,它解釋widget是element的configuration。我們暫且先不管那個element(未來會介紹)到底是什麼東西好惹,光是把widget說成configuration本身的意思就很讓人耐人尋味。我當初看到這段描述時是完全摸不著頭緒,有種傷害性不大,污辱性極強的fu~WTF我90%的時間都是花在撰寫設定檔上??

但是當我開始理解widget所扮演的職責以及element與render object是什麼東東以後,我才漸漸有一種醍醐灌頂豁然開朗的感覺。接下來讓我用一個非常簡單的例子來狡辯解釋一下


在畫面顯示一個長度300的綠色正方形


class MyApp extends StatelessWidget {
  const MyApp({super.key, required this.players});

  final List<Player> players;

  @override
  Widget build(BuildContext context) {
    return Container(
        padding: const EdgeInsets.all(20),
        width: 300,
        height: 300,
        color: Colors.green,
      );
  }
}

從上面代碼中我們主要就是在build方法裡寫一個Container widget把width和high設成300和把color設定為Colors.green,這樣畫面就會出現一個長寬都是300的綠色正方形。

怎麼樣,是不是有種撰寫config file味兒了?
其實畫面就是使用不同widget並且把想要的數值設定進去變成一份config file給framework產生畫面的過程罷了。

有了這層理解我們提高一點難度來看一個有趣的widget,一個所有開發者一定會使用到的widget Container

Container Widget

在開始之前大家可以猜猜看container是如何實作的?它可以設定color/padding/size/...等等等,簡直是widget萬花筒可能以為裡面用了什麼屌炸天的黑魔法....

  /// Creates a widget that combines common painting, positioning, and sizing widgets.

首先我們來看看Contianer source code裡寫的註解,裡面提到一個很關鍵的點combines多種不同的widgets,所以按照註解來猜測設計思路應該是把不同的widget都放在container中,依照呼叫端填入的參數,來決定使用哪些widget。

接下來我繼續看到Container build method(因為代碼不常我就全部貼出來了,大家可以花點時間看完它,如果有任何看不懂的歡迎在下面留言提問我會很榮幸地回答你們的)

  @override
  Widget build(BuildContext context) {
    Widget? current = child;

    if (child == null && (constraints == null || !constraints!.isTight)) {
      current = LimitedBox(
        maxWidth: 0.0,
        maxHeight: 0.0,
        child: ConstrainedBox(constraints: const BoxConstraints.expand()),
      );
    }

    if (alignment != null)
      current = Align(alignment: alignment!, child: current);

    final EdgeInsetsGeometry? effectivePadding = _paddingIncludingDecoration;
    if (effectivePadding != null)
      current = Padding(padding: effectivePadding, child: current);

    if (color != null)
      current = ColoredBox(color: color!, child: current);

    if (clipBehavior != Clip.none) {
      assert(decoration != null);
      current = ClipPath(
        clipper: _DecorationClipper(
          textDirection: Directionality.maybeOf(context),
          decoration: decoration!,
        ),
        clipBehavior: clipBehavior,
        child: current,
      );
    }

    if (decoration != null)
      current = DecoratedBox(decoration: decoration!, child: current);

    if (foregroundDecoration != null) {
      current = DecoratedBox(
        decoration: foregroundDecoration!,
        position: DecorationPosition.foreground,
        child: current,
      );
    }

    if (constraints != null)
      current = ConstrainedBox(constraints: constraints!, child: current);

    if (margin != null)
      current = Padding(padding: margin!, child: current);

    if (transform != null)
      current = Transform(transform: transform!, alignment: transformAlignment, child: current);

    return current!;
  }

從build method中我們可以很明顯的就是不同的widget一層一層包起來來達到效果。

之前我常常因為不懂Container的實作原理鬧出烏龍,例如說如果一個widget想要加20的Padding一般來說應該是這樣寫

  Padding(
      padding: const EdgeInsets.all(20),
      child:        
          Container(
              width: 300,
              height: 300,
              color: Colors.yellow,
              child: Text("widget is config"),
            ),
  )

如果widget恰好又是container你可能想說那乾脆把padding寫進container裡這樣還少包一個padding widget

 Container(
  padding: const EdgeInsets.all(20),
  width: 300,
  height: 300,
  color: Colors.yellow,
  child : Text("widget is config"),
)

此時你一定會感覺自己真是聰明讓代碼變更簡潔惹,殊不知Container是先包了Padding才包ConstrainedBox,所以Padding其實是包在child widget上。
如果想要有一般Padding的效果,要用Container的margin屬性,Padding會在ConstrainedBox包完之後才包,這就會呈現出你要的效果

總之透過Container的實作,我們可以理解widget的設計和特性也能理解為什麼widget會被視為config的原因了吧,今天大概就到這邊,如果有任合問題都歡迎提問我都會積極地回答,謝謝大家。


上一篇
第一頁(夜),勇者啟程
下一篇
第三夜,Flutter的核心(二)
系列文
Flutter你不知道又不可不知道的核心概念10
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言