Brother Cat said
This is the second part of the custom component, first one, click here
Sometimes we need to make some very basic components or tools, we need to control rendering, size changes, preprocessing, and destruction
This article is about how to encapsulate a responsive ChangeSize component, which inherits SingleChildRenderObjectWidget. If you are also writing similar functions, you can quickly get started with this parent class.
Old iron remember to forward, Brother Mao will present more Flutter good articles~~~~
WeChat group ducafecat
b station https://space.bilibili.com/404904528
original
https://rlesovyi.medium.com/writing-custom-widgets-in-flutter-part-2-singlechildrenderobjectwidget-5637fecdf9bb
Code
https://github.com/MatrixDev/Flutter-CustomWidgets
reference
- https://pub.flutter-io.cn/packages/get#reactive-state-manager
- https://dart.dev/guides/language/extension-methods
text
Introduction
It's time for me to write my second article. This time it will be a very simple widget, and it will notify us when its sub-size changes. This task is very simple, but its main purpose is to show you how to manage child objects in RenderObject.
When I first started learning Flutter, it was one of my problems, even to complete the Udemy course. Unfortunately, I didn't get my answer. On StackOverflow, people suggest to use GlobalKey on Widget, find its RenderObject and get its size.
Although there is nothing wrong with the above solution, I still don't like some of its aspects:
- It changes the way the Widget element is destroyed
- You need to add imperative code to the declarative widget structure
- There is no ability to actually track the size of the widget, it needs to be pulled as needed
Generally speaking, the goals I want to achieve are:
return ChildSize(
child: buildChildWidget(),
onChildSizeChanged: (size) => handleNewChildSize(size),
);
Simple theory
When writing a custom widget that contains child windows, we need to know some important things:
- For each custom widget, we need to write its Element and (sometimes) RenderObject implementation
- The element will expand its child elements Widgets into separate elements and update/recreate them when needed
- Few important roles--child management, layout, drawing, and hit testing (mouse pointer, touch events, etc.)
Code
First, we need to declare an actual Widget:
class ChildSize extends SingleChildRenderObjectWidget {
final void Function(Size)? onChildSizeChanged;
const ChildSize({
Key? key,
Widget? child,
this.onChildSizeChanged,
}) : super(key: key, child: child);
}
There is nothing new here, except for SingleChildRenderObjectWidget. This is a helper in the Flutter framework, which allows us to write custom widgets with no more than one child window. This greatly simplifies our code, because we don't need to write custom Element at all.
The only thing we need to add to the Widget is to create a RenderObject and update it when the Widget changes:
class ChildSize extends SingleChildRenderObjectWidget {
// ...
@override
RenderObject createRenderObject(BuildContext context) {
return RenderChildSize().._widget = this;
}
@override
void updateRenderObject(BuildContext context, RenderChildSize renderObject) {
renderObject.._widget = this;
}
}
Now we need to create the render object:
class RenderChildSize extends RenderBox
with RenderObjectWithChildMixin<RenderBox> {
var _widget = const ChildSize();
}
It is a special mixin, we must add it when using SingleChildRenderObjectWidget. This mixin will handle all the boring stuff (see next article). Almost every helper of this type needs to add some mixins. You can find these requirements in the documentation of each helper.
The next thing to do is to lay out our 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);
}
}
}
During the layout process, we must decide the size of the rendered object. To do this, we need to decorate our children. The size of the rendered object will be the same as the size of the child object (we don't have any padding, margins, etc.).
Here are some important notes:
- We must pass the parentUsesSize = true child layout function to get its size afterwards. Otherwise, an exception will be thrown. Thanks to this flag Flutter can add additional optimizations
- There may be such a situation, even if we have a child Widget, it will not have its child RenderObject. Not all gadgets have rendering objects. In this case, if there are any recent nested render objects, Flutter will try to provide us
In this method, we also check whether the size has changed, and call the callback when it changes.
The last thing we need to do is to delineate our child and route the hit test event:
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;
}
}
The results are as follows:
© Cat brother
Past
Open source
GetX Quick Start
https://github.com/ducafecat/getx_quick_start
News client
https://github.com/ducafecat/flutter_learn_news
strapi manual translation
WeChat discussion group ducafecat
Series collection
Translation
https://ducafecat.tech/categories/%E8%AF%91%E6%96%87/
Open source project
https://ducafecat.tech/categories/%E5%BC%80%E6%BA%90/
Dart programming language basics
https://space.bilibili.com/404904528/channel/detail?cid=111585
Getting started with Flutter zero foundation
https://space.bilibili.com/404904528/channel/detail?cid=123470
Flutter actual combat from scratch news client
https://space.bilibili.com/404904528/channel/detail?cid=106755
Flutter component development
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
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。