貓哥說
這是自定義組件的第二篇, 第一篇點(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://github.com/MatrixDev/Flutter-CustomWidgets
參考
- https://pub.flutter-io.cn/packages/get#reactive-state-manager
- https://dart.dev/guides/language/extension-methods
正文
介紹
我寫第二篇文章的時(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é)果如下:
? 貓哥
往期
開源
GetX Quick Start
https://github.com/ducafecat/getx_quick_start
新聞客戶端
https://github.com/ducafecat/flutter_learn_news
strapi 手冊譯文
微信討論群 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