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

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

https://ducafecat.tech/

https://github.com/ducafecat

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

https://getstrapi.cn

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


独立开发者_猫哥
666 声望126 粉丝