directory

Why Dart development language is used for Flutter 1. 2.1 How Flutter Engine 2.2 Framework(Dart) 3. How Flutter builds THE UI through widgets 4.Flutter is a responsive Framework, but does not change as long as it is functional 5. The huge system of widgets brings high learning costs as well as convenience. 7. A good cross-platform UI framework must have good UI debugging tools. 2.1 Open event communication: Platform Channel 2.2 Open cross-layer rendering: External Texture


Why does Flutter use Dart development language

  • Dart runtime and compiler support two key features of Flutter: adoption in the development phase, JIT mode, no compilation required for changes, greatly saving development time; AOT can be used to generate efficient ARM code at release time to ensure application performance.
  • Dart also supports static type checking, which is an advantage over JavaScript when it was developed.
  • The Flutter framework uses functional streams, which makes it heavily dependent on the underlying memory allocator, whereas Dart uses the Chrome V8 engine for memory allocation, which makes memory allocation guaranteed.
  • Dart enables Flutter to eliminate the need for a separate declarative layout language, such as JSX or XML, or a separate visual interface builder, because Dart’s declarative programming layout is easy to read and visualize. With all layouts in one language and clustered in one place, Flutter easily provides advanced tools to make the layout simpler
  • Because Flutter applications are compiled to Native code, they do not need to build slow Bridges between domains (for example, RN needs to communicate between JavaScript and Native), and it starts much faster.

Ii. The UI system of Flutter

Characteristics of 1.

  • Flutter does not use webView or native controls of the operating system

  • Flutter uses its own high-performance rendering engine, Skia, to draw widgets. This ensures UI consistency on Both Android and iOS, and avoids the limitations and high maintenance costs associated with native controls dependency.

  • Composition larger than Inheritance Controls themselves are typically made up of many small, single-purpose controls that combine to create powerful effects, and the hierarchy of classes is flat to maximize the number of possible combinations

2. Architecture Introduction

2.1 Flutter Engine

The Flutter engine is a portable runtime that hosts Flutter applications. It implements the core libraries of Flutter, including animation and graphics, file and network I/O, accessibility support, plug-in architecture, and Dart runtime and compilation toolchains. Most developers will interact with Flutter through the Flutter framework, which provides a modern, responsive framework, as well as a rich set of platforms, layouts, and base widgets.

2.2 Framework (Dart)

This is a pure Dart implementation SDK that implements a set of base libraries, from the bottom up. Let’s take a quick look at it:

  • The bottom two layers (Foundation and Animation, Painting, and Gestures) are merged into a DART UI layer in some Google videos, corresponding to the DART: UI package in Flutter, which is the underlying UI library exposed by the Flutter engine. Provides animation, gesture and drawing capabilities.

  • The Rendering layer is an abstract layout layer that relies on the DART UI layer. The Rendering layer builds a UI tree, calculates the changes when the TREE changes, updates the tree, and draws the TREE onto the screen. The Rendering layer is similar to the React virtual DOM. The Rendering layer is the core part of the Flutter UI framework, which determines the location and size of each UI element and performs coordinate transformation and Rendering (calling the underlying DART: UI).

  • The Widgets layer is the base library that Flutter provides on top of the base library. Flutter also provides libraries of Components in the Material and Cupertino visual styles. Most of the scenarios we’ve developed for Flutter only deal with these two layers.

In Flutter, almost everything is a widget. Applications, pages, layouts, views, events, notifications, and even specific text styles. Unify the Flutter code as a widget.

The widget of Flutter is a description of the page UI, similar to HTML on the Web, XIB on iOS, and XML on Android. Flutter also forms a widget tree during the UI building process, just like the iOS view tree. But the difference is that this tree is not the final rendered tree.

3. How does Flutter build its UI from widgets

Take a look at Flutter’s render pipeline first:

The rendering process goes from widget tree to Element tree to renderObject tree, as follows:

  • Widgets: Store render content, view layout information, and preferably immutable properties of widgets. Check back)

  • Element: Holds the context, traversing the view tree through Element, which holds both widgets and renderObjects

  • RenderObject: Creates a layout based on the Widget’s layout properties, and paints the content passed to the Widget

Element adds context information to widgets. Element is the instantiation node of the corresponding widget in the render tree. The same widget can correspond to multiple elements in the render tree, like a view template.

Widgets are immutable and cannot be changed after their initial state is set. That is, each update to the view rebuilds the widget itself and its child widgets (in the form of re-executing the widget’s build method).

Flutter introduces State to manage the State of a view when it changes at runtime. After modifying the data, you need to actively call setState() to trigger an update of the view’s state. Unlike normal bidirectional binding, any data modification triggers a change in the view, making it easy for the view to update the rendering multiple times in a short period of time. It can also be seen that the designers of Flutter do not want you to update the view state frequently, since rebuilding the widget tree is expensive, especially for complex pages.

In addition, Flutter summarizes and compares events at a given moment in time in the Element layer between the widget and the real rendered RenderObject. Flutter makes minimal changes to the real rendered RenderObject tree, synchronizing only those that really need to be modified. To improve rendering efficiency.

4. Flutter is a responsive framework, but does not change as long as its potential is unchanged

Have the following characteristics of a responsive framework

  • Instead of manipulating the UI directly, drive view changes by modifying data and then updating the view’s state
  • Manipulate data through binding of view events and ultimately react the results to the view

The core idea of Flutter on page rendering is simple is fast. Therefore, a StatelessWidget with an immutable state is designed instead of a mutable state widget, which emphasizes the idea that Flutter cannot change while it can.

5. The huge system of widgets brings high learning costs as well as convenience

Flutter has a large architecture of components, with many Cupertino and Material style widgets ready to use, making it relatively easy to build a UI. However, the convenience of a large component architecture also comes with a high learning cost (it takes time to memorize the general features of these widgets).

Thankfully, there aren’t that many widgets you use. As mentioned above, widgets are only interface descriptions. There are many ways to implement the same interface, and everyone will build the interface in a way they are familiar with and good at. However, after converting to an Element tree, the RenderObject tree may end up being the same. There is a sense that all roads lead to the same destination.

Take a look at some of the common Flutter widgets below.

6. Doll UI code, uncover a layer and another layer, drink this cup there are three more cups

Because Flutter is basically implemented by widgets, it is difficult to avoid a layer upon layer code style that is htMl-like.

  • One layer of control unit
  • A layer of container decoration (rounded corners, colored, etc.)
  • Event sets one layer
  • Layout sets N layers
  • Parent controller suite Layer N……
  • Page also to set a layer

It’s a little abstract, so let’s do a real example.

Here is the view code for the Cell:

Column(// children: <Widget>[Padding(// margin: EdgeInsets. All (10)), child: Row(// children: <Widget>[ClipRRect(// Cut rounded corners borderRadius: Borderradius.circular (10.0), Child: image.asset ('images/icon.png',width: 80,height: 80),), padding-back (// padding-back: const EdgeInsets. Only (left: 10), child: Column (/ / vertical columns crossAxisAlignment: crossAxisAlignment. Start, children: < widgets > [Text (/ / Text control'Vanilla latte', style: TextStyle(// Text style fontSize: 18, color: color.black),), Text('Vanilla Latte',
                              style: TextStyle(
                                  fontSize: 14,
                                  color: Color(0xffcccccc)
                              ),
                            ),

                            Text(
                              'Default: large/monosaccharide/hot',
                              style: TextStyle(
                                  fontSize: 14,
                                  color: Color(0xffcccccc)
                              ),
                            ),

                            Text(
                              '¥27', style: TextStyle(fontSize: 17, color: color.black),),),), Expanded(// Fill the remaining space of the parent container child: Row(mainAxisAlignment: mainAxisAlignment. End,// right-align children: <Widget>[GestureDetector(onTap: (){// Click the event trigger}, child: BorderRadius: borderRadius. Circular (10.0), child: Container(// Container decoration, used to add a blue background color: color.blue, child: Add (// Icons. Add, size: 20, color: color.white)),)],),),),),), Container(color: Color(0xffcccccc), height: 0.5)],);Copy the code

It’s a little better to have an auxiliary line and a trailing comment in the IDE, but it’s a bit hard for me to get used to the iOS code style (although I’ve been getting used to it for a while) :

Maybe, like me, you think of encapsulation. Okay, let’s encapsulate it.

// Cell whole Column(children: <Widget>[getContent(),/*cell content */ getBottomLine()/* dividing line */],); /* Cell content */ WidgetgetContent() {returnAll (10), child: Row(children: <Widget>[getHeadIcon(),/* head */ Padding(/* middle text column */ Padding: Const EdgeInsets. Only (left: 10), child: getMiddleWidget(),), Expanded(/* Fills the remaining space of the parent container */ child: GetRightButton ()/* button */)],),); } /* Splitter */ WidgetgetBottomLine() {returnContainer(color: color (0xffcccccc), height: 0.5); } /* Avatar */ WidgetgetHeadIcon() {returnClipRRect(// Cut corners borderRadius: borderRadius. Circular (10.0), Child: image.asset ('images/icon.png',width: 80, height: 80), ); } /* Middle text column */ WidgetgetMiddleWidget() {
  return Column(
    crossAxisAlignment: CrossAxisAlignment.start,
    children: <Widget>[
      getText('Vanilla latte', 18, Colors.black),
      getText('Vanilla Latte', 14, Color(0xffcccccc)),
      getText('Default: large/monosaccharide/hot', 14, Color(0xffcccccc)),
      getText('¥27', 17, Colors.black) ], ); } /* Right button */ WidgetgetRightButton() {returnRow(mainAxisAlignment: mainAxisAlignment. End,// right-align children: <Widget>[GestureDetector(onTap: (){// Click the event trigger}, child: BorderRadius: borderRadius. Circular (10.0), child: Container(color:Colors. Blue, child: Icon( Icons.add, size: 20, color: Colors.white ) ), ), ) ], ); } /* Text */ Text getText(Text, double fontSize, Color Color){return Text(
    text,
    style: TextStyle(
        fontSize: fontSize,
        color: color
    ),
  );
}
Copy the code

The above is a more detailed packaging, of course, because there are many levels, it is not impossible to continue to split, which involves the packaging granularity and the final result of packaging can be proportional. Take a look at the structure:

  • The cell as a whole
  • The cell contents
    • Head portrait
    • Text columns
      • The text
    • button
  • The divider

Above, after splitting relatively better, but a layer of a layer of criticism or unavoidable. (For example, the cell content function and the right button function are not considered because this is an unconventional way of implementing a button, usually using the button widget of Flutter.)

In my opinion, the main reason for this result is its biggest feature: everything widget, widget package widget.

It’s worth thinking about the granularity of your layout if you want your code to be elegant.

7. A good cross-platform UI framework must have good UI debugging tools

The Visual view tree viewing tool is provided in the Flutter Inspector, which is unfortunately 2D compared to Xcode’s interface debugging tool, but it is quite powerful. The diagram below:

More tools
  • Performance Overlay Allows you to view frame rates of the GPU and UI

  • Paint Baselines

  • Debug Paint displays Paint boundaries for all controls. Green arrows indicate scrollable content and the orientation from start to end of the scrollable content

Because the Widget Tree is not the final drawn UI Tree, the Flutter monitor also provides a real drawing Tree viewing tool, as shown in the Render Tree column below.

The new plugin for Flutter (32.0.1) provides simultaneous localization of code, which is getting better and better

These tools are sufficient for normal development; I’ll leave the details to the reader.

3. Flutter interacts with the native

1. The choice of mixed dependency schemes

1.1 The default construction method of Flutter, native engineering is completely the product of Flutter construction

  • Native reversely relies on the parent of the Flutter and is heavily coupled
  • Code bases are difficult to split and manage
  • Invasion of purely native development team members requires a complete Flutter development environment and corresponding build steps

1.2 The three code bases are independent. Modify the Flutter construction process to directly provide the build products to Native as a dependency

In this approach, iOS is used as an example to make a local POD dependency of Flutter. Framework and related plug-ins. Resources are also copied locally for maintenance. The Flutter is then packaged into a POD library, which is a black box for native team members to use. References to the Flutter Pod library need to be generated by each team member through the Flutter build process. Although the code repository is easier to separate, there are drawbacks:

  • Slightly more complex changes are needed to Flutter’s original construction process
  • The Native works and the contents of the Flutter are still coupled locally
  • Native developers still need a complete Flutter development environment

1.3 Change the local dependencies of Flutter to remote dependencies, and native development completely disintegrates Flutter

This solution is to place all of Flutter dependencies in a separate remote repository. Native references Flutter as if it were a public tripartite repository. At this point, Native does not need the Flutter development environment. The disadvantage of this solution is that the synchronization process becomes more cumbersome. Changes to Flutter contents need to be synchronized to remote repositories and then to native dependencies. In extreme cases, the dependency libraries need to be updated frequently when native interacts with Flutter frequently. Managing the corresponding versions of the Flutter dependent libraries and native code versions also requires additional effort. However, this is not a big problem, and the previous H5 and native mix similar, can be used.

2. It depends on martial arts

Flutter uses Dart to build its own UI framework based on SKIA. The underlying layer of Flutter is ultimately drawn by OpenGL, and the UI is isolated between Native and the Flutter Engine. Developers write UI code without worrying about platform implementation, making it cross-platform. This layer of isolation creates a mountain between the Flutter Engine and the Native, requiring a different way to communicate.

2.1 Enabling Event Communication: Platform Channel

Communication between Flutter and native relies on a flexible message delivery method: the Platform Channel. Platform refers to the platform that Flutter runs on, such as Android or IOS. It can be considered as the native part of the application. The platform channel is the communication bridge between Flutter and the native.

Platform channel capabilities

  • Pass small amounts of data: basic data types, arrays, dictionaries, binary data;
  • Big data blocks can be delivered by customization, but the transmission of big data such as images and videos inevitably causes huge consumption of memory and CPU
  • Non-thread-safe, native callbacks must be executed on the main thread, so time-consuming operations should be handled in the Native Handler

Platform channels are not designed to deliver big data, but essentially provide a messaging mechanism.

2.2 Open image Rendering: External Texture

Texture: Can be understood as an object within the GPU that represents image data. Flutter provides a Texture control that displays data provided by Native.