Zero: preface

1. Series of introduction

The first thing you might think about Flutter painting is to use the CustomPaint component to create a custom CustomPainter object. All visible components of a Flutter, such as Text, Image, Switch, Slider, and so on, are drawn. However, most of the components of a Flutter are not drawn using the CustomPaint component. The CustomPaint component is a wrapper around the underlying painting of the framework. This series is an exploration of Flutter drawing, testing, debugging, and source code analysis to reveal things that are overlooked or never known when drawing, and points that can go wrong if omitted.

  • Flutter drawing exploration 1 | CustomPainter refresh the correct posture
  • Flutter drawn to explore 2 | comprehensive analysis CustomPainter related classes
  • Flutter draw explore CustomPainter class 3 | in-depth analysis
  • Flutter draw explore 4 | in-depth analysis setState reconstruction and renewal
  • Flutter draw redraw range RepaintBoundary explore 5 | in-depth analysis
  • Flutter CustomPaint components map to explore 6 | in-depth analysis

2. Non-custompaint drawing

The previous six articles should have covered the CustomPaint component pretty well. But CustomPaint is used in the source code with only about 20 components, and most of the visible components are drawn in other ways. When you dig into the drawing of these components, you’ll see that both CustomPaint and other components end up drawing based on RenderObject#paint. What’s the difference between CustomPaint and RenderObject#paint?

The advantage is that CustomPaint, as a wrapper, internally maintains common logic for RenderCustomPaint rendering objects. The biggest benefit of this is to encapsulate the operations related to RenderObject and expose the CustomPainter abstraction to the user, providing the interface to draw. This way, the framework user doesn’t have to deal with the RenderObject, and can draw methods using the Canvas callback.

The downside: The lower down the ladder, the more maneuverable it is, the more flexible it is, and the more complex it is to use or understand. Conversely, the higher the level of encapsulation, the less maneuverability, the more rigid, the easier to use or understand. There are sacrifices to be made for ease of use. CustomPainter exposes very limited manipulation, and refreshing and sizing controls are not as flexible as using RenderObject directly.

Stop only at the top of the use, although it will not affect you to make things. But if you can see it from the bottom up, you know what it is and why. Confusion and doubt can give a powerful analysis from the principle, it is not used to be timid, and there will be a certain amount of resilience when things go wrong. This article introduces several non-CustomPainter drawn components to see how RenderObject is used in the source code.


ColoredBox source code analysis

Test cases

The role of ColoredBox is to fill its size area with color. The color attribute of the Container component source code is implemented by integrating the component.

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ColoredBox(
      color: Colors.green,
      child: SizedBox(
        height: 200,
        width: 200,),); }}Copy the code

ColoredBox component source code

ColoredBox inherited from SingleChildRenderObjectWidget, that it can have a child, and belongs to RenderObjectWidget gens. Use it to create and update renderObjects, and you can see that the relevant RenderObject here is _RenderColoredBox. That is, the rendering is done in the _RenderColoredBox.

class ColoredBox extends SingleChildRenderObjectWidget {
  
  const ColoredBox({@required this.color, Widget child, Key key})
      : assert(color ! =null),
        super(key: key, child: child);

  final Color color;

  @override
  _RenderColoredBox createRenderObject(BuildContext context) {
    return _RenderColoredBox(color: color);
  }

  @override
  void updateRenderObject(BuildContext context, _RenderColoredBox renderObject) {
    renderObject.color = color;
  }
	/ / a little...
}
Copy the code

3._RenderColoredBoxRender object source code

Here is the full source code for _RenderColoredBox. In the paint method, rectangles are drawn using the color passed in when the Size is greater than sie.zero. Render objects form a tree structure called a render tree. If the _RenderColoredBox child is not empty, the child render object is drawn.

class _RenderColoredBox extends RenderProxyBoxWithHitTestBehavior {
  _RenderColoredBox({@required Color color})
    : _color = color,
      super(behavior: HitTestBehavior.opaque);

  Color get color => _color;
  Color _color;
  set color(Color value) {
    assert(value ! =null);
    if (value == _color) {
      return;
    }
    _color = value;
    markNeedsPaint();
  }

  @override
  void paint(PaintingContext context, Offset offset) {
    if (size > Size.zero) {
      // tag 1: Draw rectanglecontext.canvas.drawRect(offset & size, Paint().. color = color); }if(child ! =null) {
      // Tag 2: If the child is not empty, draw the childcontext.paintChild(child, offset); }}}Copy the code

RenderCustomPaint is the same as the CustomPaint component, except that the drawing method is implemented here, and RenderCustomPaint abstracts the drawing logic away for the user to handle.


2. Picture drawing and analysis
1. The Image components

The Image component is a StatefulWidget whose State depends on other widgets for building tasks and does not create a rendered object itself. As follows, _ImageState mainly relies on RawImage to build.


RawImage inherits LeafRenderObjectWidget. It is a RenderObjectWidget, so it needs to create and maintain RenderObject.


RenderImage RawImage#createRenderObject returns the RenderImage, which is a RenderObject, meaning that the image will be drawn by this object.


2.RenderImage

RenderImage is a RenderObject, and we’ll just look at its paint method. As follows, when _image is not null, the paintImage method is executed to pass in the canvas and the required draw parameters.

In the paintImage method, this is ultimately done through the canvas drawing API. So the parameters we pass into the Image component can be found in the RenderImage using the scene and function.


3. Text drawing and analysis

1. The Text component

The Image component is a StatelessWidget, a class of components that rely on other widgets for build tasks. It is not responsible for creating render objects itself. Below, Text mainly relies on RichText to build.


RichText inherited from MultiChildRenderObjectWidget, is a RenderObject object. So you need to complete the task of creating and maintaining the RenderObject.


Text#createRenderObject returns the RenderParagraph, which is a RenderObject, meaning that the rendering of the text will be done by this object.


2.RenderParagraphApply colours to a drawing object

RenderParagraph is a RenderObject object, and we’re just looking at its paint method. As follows, the text is drawn using the — textPainter member.


TextPaint#paint completes the text drawing with canvas.drawParagraph.

As you can see, the component is not drawn by itself, but by the corresponding RenderObject. RenderObject has another important task besides drawing, which is layout. So RenderObject is a very important class within the Flutter framework. Unlike widgets, a RenderObject has a longer life, and when rebuilt, only the Widget object is updated and the RenderObject is updated with the information provided by the new Widget. This is also a very nice treatment of the Flutter frame. Paints explore 4 | Flutter in the thorough analysis on this setState reconstruction and renewal in detail.


Widget-element-renderObject

1. The Widget components

Widgets are the first objects we touch, and their biggest feature is that all member properties need to be final. This means that a family object cannot modify its configuration properties once instantiated. When a new value is needed, the object with the new configuration information is recreated. It’s cannon fodder. According to the inheritance relationship, it can be roughly divided into the following five types:

[1]. StatelessWidget Immutable state component [2].statefulWidget mutable state component [3]. ProxyWidget Proxy component [4]. PreferredSizeWidget fixed-size component [5RenderObjectWidget Render object componentCopy the code

In fact, I prefer to separate widgets into two types: composite widgets and rendered widgets. The first four widgets above are all composed from existing widgets and do not maintain RenderObject.


2. The Element Element

The main use of widgets in the Flutter framework is to create elements. Elements are divided into two categories: ComponentElement and RenderObjectElement. The root Element#mount creates a tree structure of elements by triggering the mount of the child elements in turn.

RenderObjectElement holds the RenderObject member, which is created by RenderObjectWidget. This sentence is the most important relationship among Element, RenderObject, and Widget. A ComponentElement doesn’t hold a RenderObject, so it has nothing to do with the RenderObject, just a Component as its name calls it.


E.g. < 1 > Render objects

RenderObject is held by RenderObjectElement and created by RenderObjectWidget. It is instantiated when RenderObjectElement#mount is created and attached to the render tree, forming the render tree sequentially.

The RenderObject is responsible for drawing paint and layouts, and is the core object. Both visual and layout components rely on RenderObject for their functional implementation. If we are capable enough, we can also follow the processing in the source code and implement RenderObject for drawing and layout.


This concludes the series. Seven days watch, seven days clock. Two years ago, I first came into contact with Flutter in seven days. However, at the beginning, the knowledge about Flutter was very little and the level of Flutter was low, and non-standard use was also difficult. With the deepening of my understanding of Flutter, I hope to present a more real world of Flutter through my own sharing here. Through these seven articles, I hope to give you a more comprehensive understanding of Flutter, especially in terms of drawing. By understanding the internal realization of Flutter, you will be able to move around with ease. Here is a close-up of the seven:

  • Flutter drawing exploration 1 | CustomPainter refresh the correct posture
  • Flutter drawn to explore 2 | comprehensive analysis CustomPainter related classes
  • Flutter draw explore CustomPainter class 3 | in-depth analysis
  • Flutter draw explore 4 | in-depth analysis setState reconstruction and renewal
  • Flutter draw redraw range RepaintBoundary explore 5 | in-depth analysis
  • Flutter CustomPaint components map to explore 6 | in-depth analysis
  • Flutter drawing exploration CustomPaint 7 | not used for drawing

@Zhang Fengjietele 2021.01.17 not allowed to transfer my public number: the king of programming contact me – email :[email protected] – wechat :zdl1994328 ~ END ~