猫哥说

这是自定义组件的第二篇, 第一篇点这里

有的时候咱们须要做些很根底的组件或者工具,咱们须要管制渲染、尺寸变动、预处理、销毁

这篇文章是写对于如何封装一个响应式的 ChangeSize 组件,组件继承了 SingleChildRenderObjectWidget,如果你也在写相似的性能,用这个父类能够疾速的上手。

老铁记得 转发 ,猫哥会出现更多 Flutter 好文~~~~

微信群 ducafecat

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

原文

https://rlesovyi.medium.com/w...

代码

https://github.com/MatrixDev/...

参考

  • https://pub.flutter-io.cn/pac...
  • https://dart.dev/guides/langu...

注释

介绍

我写第二篇文章的时候到了。这次它将是一个非常简单的小部件,当它的子大小发生变化时,它会告诉咱们。这个工作非常简单,然而它的次要目标是向您展现如何在 RenderObject 中治理子对象。

当我刚开始学习 Flutter 的时候,它是我的问题之一,甚至是实现 Udemy 的课程,很遗憾,我没有失去我的答案。在 StackOverflow 上,人们倡议在 Widget 上应用 GlobalKey,找到它的 RenderObject 并获取它的大小。

尽管上述解决方案没有任何问题,但我依然不喜爱它的一些中央:

  • 它扭转了 Widget 元素的销毁形式
  • 您须要在申明性小部件构造中增加命令式代码
  • 没有能力理论跟踪小部件的大小,它须要依据须要拉

一般来说,我想要达到的指标是:

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

简略的实践

当编写一个蕴含子窗口的自定义窗口小部件时,咱们须要晓得一些重要的事件:

  • 对于每个自定义小部件,咱们须要编写它的 Element 和(有时) RenderObject 实现
  • 元素将扩大其子元素 Widgets 为独自的元素,并在须要时更新/从新创立它们
  • 简直没有什么重要的角色ーー子代治理、布局、绘制和命中测试(鼠标指针、触摸事件等)

代码

首先,咱们须要申明一个理论的 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 框架中的一个帮手,它容许咱们编写不超过一个子窗口的自定义窗口小部件。这大大简化了咱们的代码,因为咱们基本不须要编写定制的 Element。

咱们惟一须要增加到 Widget 中的是创立 RenderObject,并在 Widget 更改时更新它:

class ChildSize extends SingleChildRenderObjectWidget {  // ...  @override  RenderObject createRenderObject(BuildContext context) {    return RenderChildSize().._widget = this;  }  @override  void updateRenderObject(BuildContext context, RenderChildSize renderObject) {    renderObject.._widget = this;  }}

当初咱们须要创立渲染对象:

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

是一个非凡的 mixin,咱们在应用 SingleChildRenderObjectWidget 时必须增加它。这个 mixin 将解决所有无聊的货色(请参阅下一篇文章)。简直这种类型的每个帮忙器都须要增加一些 mixin。您能够在每个帮忙器的文档中找到这些要求。

下一步要做的是布局咱们的 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);    }  }}

在布局过程中咱们必须决定渲染对象的大小。要做到这一点,咱们须要安排咱们的孩子。渲染对象的大小将与子对象的大小雷同(咱们没有任何填充、边距等)。

这里有一些重要的注意事项:

  • 咱们必须通过 parentUsesSize = true 子布局函数,以便预先失去它的大小。否则将抛出异样。感激这个 flag Flutter 能够增加额定的优化
  • 可能有这样一种状况,即便咱们有一个子 Widget,也不会有它的子 RenderObject。并不是所有的小工具都有渲染对象。在这种状况下,如果存在任何最近的嵌套渲染对象,Flutter 将尝试提供给咱们

在这个办法中,咱们还查看大小是否产生了变动,并在发生变化时调用回调。

咱们须要做的最初一件事就是描述咱们的 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;  }}

后果如下:


© 猫哥

https://ducafecat.tech/

https://github.com/ducafecat

往期

开源

GetX Quick Start

https://github.com/ducafecat/...

新闻客户端

https://github.com/ducafecat/...

strapi 手册译文

https://getstrapi.cn

微信探讨群 ducafecat

系列汇合

译文

https://ducafecat.tech/catego...

开源我的项目

https://ducafecat.tech/catego...

Dart 编程语言根底

https://space.bilibili.com/40...

Flutter 零根底入门

https://space.bilibili.com/40...

Flutter 实战从零开始 新闻客户端

https://space.bilibili.com/40...

Flutter 组件开发

https://space.bilibili.com/40...

Flutter Bloc

https://space.bilibili.com/40...

Flutter Getx4

https://space.bilibili.com/40...

Docker Yapi

https://space.bilibili.com/40...