The cat said

This is the second article on custom components. Click here for the first

Sometimes we need to do very basic components or tools, we need to control rendering, sizing, preprocessing, destruction

This article is written about how to encapsulate a responsive ChangeSize components, inherited SingleChildRenderObjectWidget components, if you were to write a similar function, use the parent class can quickly get started.

Old iron remember to forward, Brother Cat will present more Flutter good articles ~~~~

Ducafecat WeChat group

B stationspace.bilibili.com/404904528

The original

Rlesovyi.medium.com/writing-cus…

code

Github.com/MatrixDev/F…

reference

  • Pub. Flutter – IO. Cn/packages/ge…
  • The dart. Dev/guides/lang…

The body of the

introduce

It’s time for my second article. This time it will be a very simple widget that notifies us when its child size changes. This task is fairly 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 questions, even after completing the course of Udemy. Unfortunately, I did not get my answer. On StackOverflow, it is recommended to use GlobalKey on the Widget, find its RenderObject and get its size.

While there’s nothing wrong with the above solution, there are some things I still don’t like about it:

  • It changes how Widget elements are 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

In general, the goals I want to achieve are:

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

Simple theory

When writing a custom widget that contains child Windows, we need to know a few important things:

  • For each custom widget, we need to write its Element and (sometimes) RenderObject implementations
  • The element extends its child Widgets into separate elements and updates/recreates them as needed
  • * There are few important roles — child management, layout, drawing, 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);
}
Copy the code

There is nothing new here, besides SingleChildRenderObjectWidget. This is a helper in the Flutter framework that allows us to write custom widgets that are no more than one child window. This greatly simplified our code because we didn’t need to write custom Elements at all.

The only thing we need to add to the Widget is to create the RenderObject and update it when the Widget changes:

class ChildSize extends SingleChildRenderObjectWidget {
  // ...

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

  @override
  voidupdateRenderObject(BuildContext context, RenderChildSize renderObject) { renderObject.. _widget =this; }}Copy the code

Now we need to create a render object:

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

Is a special mixins, we must add it when using SingleChildRenderObjectWidget. This mixin will handle all the boring stuff (see the next article). Almost every helper of this type needs to add some mixins. You can find these requirements in the documentation for each helper.

The next step 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);
    }
  }
}
Copy the code

During the layout process we must determine the size of the render object. To do that, we need to equip our children. The render object will be the same size as the child object (we don’t have any padding, margins, etc.).

Here are some important caveats:

  • We must pass the parentUsesSize = true sub-layout function to get its size afterwards. Otherwise an exception will be thrown. Thanks to this Flag Flutter additional optimizations can be added
  • There may be a case where even if we have a child Widget, we don’t have a child RenderObject. Not all gadgets have render objects. In this case, if there are any recent nested render objects, Flutter will try to provide them to us

In this method, we also check to see if the size has changed and call the callback when it has.

The last thing we need to do is draw our Child and route hit test events:

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}) {
    returnchild? .hitTest(result, position: position) ==true; }}Copy the code

The results are as follows:


The elder brother of the © cat

ducafecat.tech/

github.com/ducafecat

The issue of

Open source

GetX Quick Start

Github.com/ducafecat/g…

News client

Github.com/ducafecat/f…

Strapi manual translation

getstrapi.cn

Wechat discussion group Ducafecat

A series of collections

The translation

Ducafecat. Tech/categories /…

The open source project

Ducafecat. Tech/categories /…

Dart programming language basics

Space.bilibili.com/404904528/c…

Start Flutter with zero basics

Space.bilibili.com/404904528/c…

Flutter combat news client from scratch

Space.bilibili.com/404904528/c…

Flutter component development

Space.bilibili.com/404904528/c…

Flutter Bloc

Space.bilibili.com/404904528/c…

Flutter Getx4

Space.bilibili.com/404904528/c…

Docker Yapi

Space.bilibili.com/404904528/c…