Flutter 編寫自定義組件 Part2.a ChildSize(with helpers)

image

貓哥說

這是自定義組件的第二篇, 第一篇點(diǎn)這里

有的時(shí)候我們需要做些很基礎(chǔ)的組件或者工具,我們需要控制渲染午阵、尺寸變化活箕、預(yù)處理、銷毀

這篇文章是寫關(guān)于如何封裝一個(gè)響應(yīng)式的 ChangeSize 組件胶征,組件繼承了 SingleChildRenderObjectWidget碗短,如果你也在寫類似的功能魁衙,用這個(gè)父類可以快速的上手。

老鐵記得 轉(zhuǎn)發(fā) 巫俺,貓哥會(huì)呈現(xiàn)更多 Flutter 好文~~~~

微信群 ducafecat

b 站 https://space.bilibili.com/404904528

原文

https://rlesovyi.medium.com/writing-custom-widgets-in-flutter-part-2-singlechildrenderobjectwidget-5637fecdf9bb

代碼

https://github.com/MatrixDev/Flutter-CustomWidgets

參考

正文

image

介紹

我寫第二篇文章的時(shí)候到了认烁。這次它將是一個(gè)非常簡單的小部件,當(dāng)它的子大小發(fā)生變化時(shí)介汹,它會(huì)通知我們却嗡。這個(gè)任務(wù)非常簡單,但是它的主要目的是向您展示如何在 RenderObject 中管理子對(duì)象嘹承。

當(dāng)我剛開始學(xué)習(xí) Flutter 的時(shí)候窗价,它是我的問題之一,甚至是完成 Udemy 的課程叹卷,很遺憾撼港,我沒有得到我的答案坪它。在 StackOverflow 上,人們建議在 Widget 上使用 GlobalKey帝牡,找到它的 RenderObject 并獲取它的大小往毡。

雖然上述解決方案沒有任何問題,但我仍然不喜歡它的一些地方:

  • 它改變了 Widget 元素的銷毀方式
  • 您需要在聲明性小部件結(jié)構(gòu)中添加命令式代碼
  • 沒有能力實(shí)際跟蹤小部件的大小靶溜,它需要根據(jù)需要拉

一般來說开瞭,我想要達(dá)到的目標(biāo)是:

return ChildSize(
  child: buildChildWidget(),
  onChildSizeChanged: (size) => handleNewChildSize(size),
);

簡單的理論

當(dāng)編寫一個(gè)包含子窗口的自定義窗口小部件時(shí),我們需要知道一些重要的事情:

  • 對(duì)于每個(gè)自定義小部件墨技,我們需要編寫它的 Element 和(有時(shí)) RenderObject 實(shí)現(xiàn)
  • 元素將擴(kuò)展其子元素 Widgets 為單獨(dú)的元素惩阶,并在需要時(shí)更新/重新創(chuàng)建它們
  • 幾乎沒有什么重要的角色ーー子代管理挎狸、布局扣汪、繪制和命中測試(鼠標(biāo)指針、觸摸事件等)

代碼

首先锨匆,我們需要聲明一個(gè)實(shí)際的 Widget:

class ChildSize extends SingleChildRenderObjectWidget {
  final void Function(Size)? onChildSizeChanged;

  const ChildSize({
    Key? key,
    Widget? child,
    this.onChildSizeChanged,
  }) : super(key: key, child: child);
}

這里沒有什么新東西崭别,除了 SingleChildRenderObjectWidget。這是 Flutter 框架中的一個(gè)幫手恐锣,它允許我們編寫不超過一個(gè)子窗口的自定義窗口小部件茅主。這大大簡化了我們的代碼,因?yàn)槲覀兏静恍枰帉懚ㄖ频?Element土榴。

我們唯一需要添加到 Widget 中的是創(chuàng)建 RenderObject诀姚,并在 Widget 更改時(shí)更新它:

class ChildSize extends SingleChildRenderObjectWidget {
  // ...

  @override
  RenderObject createRenderObject(BuildContext context) {
    return RenderChildSize().._widget = this;
  }

  @override
  void updateRenderObject(BuildContext context, RenderChildSize renderObject) {
    renderObject.._widget = this;
  }
}

現(xiàn)在我們需要?jiǎng)?chuàng)建渲染對(duì)象:

class RenderChildSize extends RenderBox
    with RenderObjectWithChildMixin<RenderBox> {
      var _widget = const ChildSize();
}

是一個(gè)特殊的 mixin,我們在使用 SingleChildRenderObjectWidget 時(shí)必須添加它玷禽。這個(gè) mixin 將處理所有無聊的東西(請(qǐng)參閱下一篇文章)赫段。幾乎這種類型的每個(gè)幫助器都需要添加一些 mixin。您可以在每個(gè)幫助器的文檔中找到這些要求矢赁。

下一步要做的是布局我們的 child:

class RenderChildSize ... {
  // ...
  var _lastSize = Size.zero;

  @override
  void performLayout() {
    final child = this.child;
    if (child != null) {
      child.layout(constraints, parentUsesSize: true);
      size = child.size;
    } else {
      size = constraints.smallest;
    }    if (_lastSize != size) {
      _lastSize = size;
      _widget.onChildSizeChanged?.call(_lastSize);
    }
  }
}

在布局過程中我們必須決定渲染對(duì)象的大小糯笙。要做到這一點(diǎn),我們需要布置我們的孩子撩银。渲染對(duì)象的大小將與子對(duì)象的大小相同(我們沒有任何填充给涕、邊距等)。

這里有一些重要的注意事項(xiàng):

  • 我們必須通過 parentUsesSize = true 子布局函數(shù)额获,以便事后得到它的大小够庙。否則將拋出異常。感謝這個(gè) flag Flutter 可以添加額外的優(yōu)化
  • 可能有這樣一種情況抄邀,即使我們有一個(gè)子 Widget耘眨,也不會(huì)有它的子 RenderObject。并不是所有的小工具都有渲染對(duì)象撤摸。在這種情況下毅桃,如果存在任何最近的嵌套渲染對(duì)象褒纲,F(xiàn)lutter 將嘗試提供給我們

在這個(gè)方法中,我們還檢查大小是否發(fā)生了變化钥飞,并在發(fā)生變化時(shí)調(diào)用回調(diào)莺掠。

我們需要做的最后一件事就是描繪我們的 child 和路由命中測試事件:

class RenderChildSize ... {
  // ...

  @override
  void paint(PaintingContext context, Offset offset) {
    final child = this.child;
    if (child != null) {
      context.paintChild(child, offset);
    }
  }

  @override
  bool hitTestChildren(BoxHitTestResult result, {required Offset position}) {
    return child?.hitTest(result, position: position) == true;
  }
}

結(jié)果如下:

image

? 貓哥

https://ducafecat.tech/

https://github.com/ducafecat

往期

開源

GetX Quick Start

https://github.com/ducafecat/getx_quick_start

新聞客戶端

https://github.com/ducafecat/flutter_learn_news

strapi 手冊譯文

https://getstrapi.cn

微信討論群 ducafecat

系列集合

譯文

https://ducafecat.tech/categories/%E8%AF%91%E6%96%87/

開源項(xiàng)目

https://ducafecat.tech/categories/%E5%BC%80%E6%BA%90/

Dart 編程語言基礎(chǔ)

https://space.bilibili.com/404904528/channel/detail?cid=111585

Flutter 零基礎(chǔ)入門

https://space.bilibili.com/404904528/channel/detail?cid=123470

Flutter 實(shí)戰(zhàn)從零開始 新聞客戶端

https://space.bilibili.com/404904528/channel/detail?cid=106755

Flutter 組件開發(fā)

https://space.bilibili.com/404904528/channel/detail?cid=144262

Flutter Bloc

https://space.bilibili.com/404904528/channel/detail?cid=177519

Flutter Getx4

https://space.bilibili.com/404904528/channel/detail?cid=177514

Docker Yapi

https://space.bilibili.com/404904528/channel/detail?cid=130578

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市读宙,隨后出現(xiàn)的幾起案子彻秆,更是在濱河造成了極大的恐慌,老刑警劉巖结闸,帶你破解...
    沈念sama閱讀 222,000評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件唇兑,死亡現(xiàn)場離奇詭異,居然都是意外死亡桦锄,警方通過查閱死者的電腦和手機(jī)扎附,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來结耀,“玉大人留夜,你說我怎么就攤上這事⊥继穑” “怎么了?”我有些...
    開封第一講書人閱讀 168,561評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵黑毅,是天一觀的道長嚼摩。 經(jīng)常有香客問我矿瘦,道長,這世上最難降的妖魔是什么匪凡? 我笑而不...
    開封第一講書人閱讀 59,782評(píng)論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮病游,結(jié)果婚禮上唇跨,老公的妹妹穿的比我還像新娘。我一直安慰自己衬衬,他們只是感情好买猖,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,798評(píng)論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著滋尉,像睡著了一般玉控。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上狮惜,一...
    開封第一講書人閱讀 52,394評(píng)論 1 310
  • 那天高诺,我揣著相機(jī)與錄音碌识,去河邊找鬼。 笑死虱而,一個(gè)胖子當(dāng)著我的面吹牛筏餐,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播牡拇,決...
    沈念sama閱讀 40,952評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼魁瞪,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了惠呼?” 一聲冷哼從身側(cè)響起导俘,我...
    開封第一講書人閱讀 39,852評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎剔蹋,沒想到半個(gè)月后旅薄,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,409評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡滩租,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,483評(píng)論 3 341
  • 正文 我和宋清朗相戀三年赋秀,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了利朵。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片律想。...
    茶點(diǎn)故事閱讀 40,615評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖绍弟,靈堂內(nèi)的尸體忽然破棺而出技即,到底是詐尸還是另有隱情,我是刑警寧澤樟遣,帶...
    沈念sama閱讀 36,303評(píng)論 5 350
  • 正文 年R本政府宣布而叼,位于F島的核電站,受9級(jí)特大地震影響豹悬,放射性物質(zhì)發(fā)生泄漏葵陵。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,979評(píng)論 3 334
  • 文/蒙蒙 一瞻佛、第九天 我趴在偏房一處隱蔽的房頂上張望脱篙。 院中可真熱鬧,春花似錦伤柄、人聲如沸绊困。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,470評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽笔喉。三九已至硝皂,卻和暖如春吧彪,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背姨裸。 一陣腳步聲響...
    開封第一講書人閱讀 33,571評(píng)論 1 272
  • 我被黑心中介騙來泰國打工傀缩, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留农猬,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,041評(píng)論 3 377
  • 正文 我出身青樓慷垮,卻偏偏與公主長得像揍堕,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子芹血,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,630評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容