flutter架构(2):Widget

flutter架构(1):概述
flutter架构(3):渲染和布局
flutter架构(4):平台嵌入混编
flutter架构(5):web支持

Widgets

As mentioned, Flutter emphasizes widgets as a unit of composition. Widgets are the building blocks of a Flutter app’s user interface, and each widget is an immutable declaration of part of the user interface.
如前所述,Flutter强调widget是组成单元。 widget是Flutter应用程序用户界面的组成部分,每个widget都是用户界面中一部分的不可变(immutable)的 声明

Widgets form a hierarchy based on composition. Each widget nests inside its parent and can receive context from the parent. This structure carries all the way up to the root widget (the container that hosts the Flutter app, typically MaterialApp or CupertinoApp), as this trivial example shows:

wdiget基于组合形成层次结构(补充:组合的概念,一定程度区别大家以往习惯的继承)。 每个widget都嵌套在其父级内部,并且可以从父级接收context。 这个结构一直到root widget(托管Flutter应用程序的容器,通常是MaterialAppCupertinoApp),如以下示例所示:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('My Home Page')),
        body: Center(
          child: Builder(
            builder: (BuildContext context) {
              return Column(
                children: [
                  Text('Hello World'),
                  SizedBox(height: 20),
                  ElevatedButton(
                    onPressed: () {
                      print('Click!');
                    },
                    child: Text('A button'),
                  ),
                ],
              );
            },
          ),
        ),
      ),
    );
  }
}

In the preceding code, all instantiated classes are widgets.
在前面的代码中,所有实例化的类都是widget。

Apps update their user interface in response to events (such as a user interaction) by telling the framework to replace a widget in the hierarchy with another widget. The framework then compares the new and old widgets, and efficiently updates the user interface.
app 通过告诉framework 用另一个widget替换层次结构中的widget来响应事件(例如用户交互),以此更新其用户界面。 然后,framework会比较新的和旧的widget,并有效地更新用户界面。

Flutter has its own implementations of each UI control, rather than deferring to those provided by the system: for example, there is a pure Dart implementation of both the iOS Switch control and the one for the Android equivalent.
Flutter对每个UI控件都有自己的实现,而不是遵循系统提供的实现:例如,纯Dart实现的iOS Switch控件Android Switch控件

iOS Switch控件
在这里插入图片描述
Android Switch控件
在这里插入图片描述

This approach provides several benefits:
这种方法具有以下优点:

  1. Provides for unlimited extensibility. A developer who wants a variant of the Switch control can create one in any arbitrary way, and is not limited to the extension points provided by the OS.
    提供无限制的可扩展性。 如果要定制Switch控件,开发人员可以用任意方式创建一个Switch控件,而不仅限于OS提供的扩展点。

  2. Avoids a significant performance bottleneck by allowing Flutter to composite the entire scene at once, without transitioning back and forth between Flutter code and platform code.
    Flutter能够一次合成整个场景,而无需在Flutter代码和平台代码之间来回转换,从而避免了明显的性能瓶颈。

  3. Decouples the application behavior from any operating system dependencies. The application looks and feels the same on all versions of the OS, even if the OS changed the implementations of its controls.
    app的表现与任何操作系统依赖项解耦。 即使操作系统更改了其控件的实现,app在所有版本的操作系统上的外观和手感也能保持一致。

Composition --组合

Widgets are typically composed of many other small, single-purpose widgets that combine to produce powerful effects.
widget通常由许多其他的小型,单一用途的widget组成,这些widget结合在一起可以产生强大的效果。

Where possible, the number of design concepts is kept to a minimum while allowing the total vocabulary to be large. For example, in the widgets layer, Flutter uses the same core concept (a Widget) to represent drawing to the screen, layout (positioning and sizing), user interactivity, state management, theming, animations, and navigation. In the animation layer, a pair of concepts, Animations and Tweens, cover most of the design space. In the rendering layer, RenderObjects are used to describe layout, painting, hit testing, and accessibility. In each of these cases, the corresponding vocabulary ends up being large: there are hundreds of widgets and render objects, and dozens of animation and tween types.
如果可以的话,尽量让设计概念简洁,但是内容丰富。 例如,在Widget层中,Flutter使用相同的核心概念Widget来表示屏幕绘制,布局(位置和大小),用户交互性,状态管理,主题,动画和导航。 在动画层中,两个概念:动画(Animations)和补间动画(Tweens),就覆盖了大部分设计空间。 在渲染层中,RenderObjects用于描述布局,绘画,命中测试(hit testing)和可访问性。 在每种情况下,对应的内容都很丰富:有数百个widget和渲染对象,以及数十种动画(Animations)和补间类型(Tweens)。

The class hierarchy is deliberately shallow and broad to maximize the possible number of combinations, focusing on small, composable widgets that each do one thing well. Core features are abstract, with even basic features like padding and alignment being implemented as separate components rather than being built into the core. (This also contrasts with more traditional APIs where features like padding are built in to the common core of every layout component.) So, for example, to center a widget, rather than adjusting a notional Align property, you wrap it in a Center widget.
(widget)类的层次结构特意设计成 浅显 而又 宽泛,以最大程度地增加可组合的数量,聚焦于每一个 小而美的可组合 widget。 核心功能是抽象的,甚至诸如填充(Padding)和对齐(Align)之类的基本功能也被实现为单独的组件,而不是内置于属性中。 (这也与更传统的API形成了对比,在传统的API中,诸如填充(Padding)之类的功能内置于每个布局组件的公共属性中。)因此,例如,将Widget 居中而不是调整名为Align的属性,而是对其进行包装 在“Center” widget中。

There are widgets for padding, alignment, rows, columns, and grids. These layout widgets do not have a visual representation of their own. Instead, their sole purpose is to control some aspect of another widget’s layout. Flutter also includes utility widgets that take advantage of this compositional approach.
有用于填充(padding),对齐(alignment),行(rows),列(columns)和网格(grids)的widget。 这些布局widget没有自己的视觉表示。 相反,它们的唯一目的是控制另一个widget的布局的某些方面。 Flutter还包括利用这种组合的方式的行成非常实用的widget。

For example, Container, a commonly used widget, is made up of several widgets responsible for layout, painting, positioning, and sizing. Specifically, Container is made up of the LimitedBox, ConstrainedBox, Align, Padding, DecoratedBox, and Transform widgets, as you can see by reading its source code. A defining characteristic of Flutter is that you can drill down into the source for any widget and examine it. So, rather than subclassing Container to produce a customized effect, you can compose it and other simple widgets in novel ways, or just create a new widget using Container as inspiration.
例如,Container,这种常用的widget,是由负责布局,绘画,定位和大小调整的几个widget组成。 具体来说,Container 由LimitedBox,ConstrainedBox,Align,Padding,DecoratedBox和Transform小部件组成,你可以通过阅读其源代码来了解它们。 Flutter的一个典型特征是您可以深入到任何widget的来源并对其进行检查。 因此,您可以将其和其他简单的widget以新颖的方式进行组合,或者仅使用Container作为灵感来创建新的小部件,而不是将Container继承以产生自定义效果。

Building widgets

As mentioned earlier, you determine the visual representation of a widget by overriding the build() function to return a new element tree. This tree represents the widget’s part of the user interface in more concrete terms. For example, a toolbar widget might have a build function that returns a horizontal layout of some text and various buttons. As needed, the framework recursively asks each widget to build until the tree is entirely described by concrete renderable objects. The framework then stitches together the renderable objects into a renderable object tree.
如前所述,您可以通过复写build() 函数,返回新的element树来确定widget的可视化展示形式。 element树更具体地表示了widget在用户界面中的作用部分。 例如,toolar widget 可能具有一个build 方法,该方法返回一些文本和各种按钮的水平布局。 根据需要,framework递归地要求每个wdiget进行构建,直到树由具体的可渲染对象完全描述为止。 然后,framework将可渲染对象契合在一起,成为可渲染对象树。

A widget’s build function should be free of side effects. Whenever the function is asked to build, the widget should return a new tree of widgets1, regardless of what the widget previously returned. The framework does the heavy lifting work to determine which build methods need to be called based on the render object tree (described in more detail later). More information about this process can be found in the Inside Flutter topic.
widget的build方法 应无副作用。 无论何时调用build,widget都应返回新的widget树,而与widget先前返回的内容无关。 framework会进行繁重的工作,根据渲染对象树(稍后将详细介绍)来确定需要调用widget 的build。 有关此过程的更多信息,请参见《深入Flutter》一文。

On each rendered frame, Flutter can recreate just the parts of the UI where the state has changed by calling that widget’s build() method. Therefore it is important that build methods should return quickly, and heavy computational work should be done in some asynchronous manner and then stored as part of the state to be used by a build method.
每一个渲染帧,Flutter可以通过调用widget的build()方法来仅重建state已更改的相关部分UI。 因此,重点是build方法应快速返回,并且繁重的计算工作应以某种异步方式完成,然后存储为要由build方法使用的state的一部分。

While relatively naïve in approach, this automated comparison is quite effective, enabling high-performance, interactive apps. And, the design of the build function simplifies your code by focusing on declaring what a widget is made of, rather than the complexities of updating the user interface from one state to another.
尽管这种方法比较幼稚,但是这种自动比较非常有效,可以实现高性能的响应式应用程序。 而且,build方法的功能设计着重于声明widget的组合,从而简化了代码,而不是将用户界面从一种状态更新为另一种状态的复杂性。

Widget state

The framework introduces two major classes of widget: stateful and stateless widgets.
framework引入了两大类小部件:stateful widget和stateless widget。

Many widgets have no mutable state: they don’t have any properties that change over time (for example, an icon or a label). These widgets subclass StatelessWidget.
许多widget没有可变state:它们没有随时间变化的任何属性(例如,icon或label)。 这些widget是StatelessWidget的子类。

However, if the unique characteristics of a widget need to change based on user interaction or other factors, that widget is stateful. For example, if a widget has a counter that increments whenever the user taps a button, then the value of the counter is the state for that widget. When that value changes, the widget needs to be rebuilt to update its part of the UI. These widgets subclass StatefulWidget, and (because the widget itself is immutable) they store mutable state in a separate class that subclasses State. StatefulWidgets don’t have a build method; instead, their user interface is built through their State object.
然后,如果需要根据用户交互或其他因素来更改widget的唯一特征,则该widget是stateful的。 例如,如果widget的计数器在用户单击按钮时递增,则计数器的值就是widget的state。 当该值更改时,需要rebuild widget以更新它的UI部分。 这些widget继承StatefulWidget,并且(因为widget本身是不可变的)它们将可变状态存储在一个单独的类中,这个类继承State类。 StatefulWidget都没有build方法。 而是通过对应State对象build它们的用户界面。

Whenever you mutate a State object (for example, by incrementing the counter), you must call setState() to signal the framework to update the user interface by calling the State’s build method again.
每当更改State对象时(例如,通过增加计数器),都必须调用setState()来通过再次调用State的build方法来向framework发出信号以更新用户界面。

Having separate state and widget objects lets other widgets treat both stateless and stateful widgets in exactly the same way, without being concerned about losing state. Instead of needing to hold on to a child to preserve its state, the parent can create a new instance of the child at any time without losing the child’s persistent state. The framework does all the work of finding and reusing existing state objects when appropriate.
具有独立性的state和widget对象可使其他widget以完全相同的方式对待stateless widget和stateful widget,而不必担心丢失state。 父容器widget无需保留子widget来保存它的state,而是可以随时创建该子widget的新实例,而不会丢失其持久state。 framework会在适当时完成所有工作:查找重复使用现有state对象。

State management --State管理

So, if many widgets can contain state, how is state managed and passed around the system?
所以,如果许多widget可以包含state,那么state如何在系统中进行管理和传递?

As with any other class, you can use a constructor in a widget to initialize its data, so a build() method can ensure that any child widget is instantiated with the data it needs:
与其他任何类一样,您可以在widget使用build函数来初始化其数据,因此build()方法可以确保使用其所需的数据实例化任何子widget:

@override
Widget build(BuildContext context) {
   return ContentWidget(importantState);
}

As widget trees get deeper, however, passing state information up and down the tree hierarchy becomes cumbersome. So, a third widget type, InheritedWidget, provides an easy way to grab data from a shared ancestor. You can use InheritedWidget to create a state widget that wraps a common ancestor in the widget tree, as shown in this example:
但是,随着widget树的深入,在树层次结构中上下传递state信息变得很麻烦。 因此,第三种小部件类型InheritedWidget提供了一种从共享祖先获取数据的简便方法。 您可以使用InheritedWidget创建一个state widget,这个state widget将公共祖先包装在widget树中,如以下示例所示:
在这里插入图片描述

Whenever one of the ExamWidget or GradeWidget objects needs data from StudentState, it can now access it with a command such as:
每当ExamWidgetGradeWidget对象中一个需要来自StudentState的数据时,它现在都可以使用以下命令来访问StudentState:

final studentState = StudentState.of(context);

The of(context) call takes the build context (a handle to the current widget location), and returns the nearest ancestor in the tree that matches the StudentState type. InheritedWidgets also offer an updateShouldNotify() method, which Flutter calls to determine whether a state change should trigger a rebuild of child widgets that use it.
of(context调用获取build context(当前widget位置的句柄),并返回树中与StudentState类型匹配的最接近的祖先。 InheritedWidgets还提供了updateShouldNotify()方法,Flutter调用该方法以确定state更改是否应触发使用它的子部件的rebuild。

Flutter itself uses InheritedWidget extensively as part of the framework for shared state, such as the application’s visual theme, which includes properties like color and type styles that are pervasive throughout an application. The MaterialApp build() method inserts a theme in the tree when it builds, and then deeper in the hierarchy a widget can use the .of() method to look up the relevant theme data, for example:
Flutter自身将InheritedWidget广泛使用共享state作为framework的一部分,例如app的视觉theme,其中包括诸如颜色和字体样式之类的属性,这些属性遍及整个app。 MaterialApp的build()方法在构建时会在树中插入一个theme,然后在层次结构的更深处,widget可以使用.of()方法来查找相关的theme数据,例如:

Container(
  color: Theme.of(context).secondaryHeaderColor,
  child: Text(
    'Text with a background color',
    style: Theme.of(context).textTheme.headline6,
  ),
);

This approach is also used for Navigator, which provides page routing; and MediaQuery, which provides access to screen metrics such as orientation, dimensions, and brightness.
这种方法也用于Navigator,它提供页面路由; 还有** MediaQuery**,可以访问屏幕指标,例如方向,尺寸和亮度。

As applications grow, more advanced state management approaches that reduce the ceremony of creating and using stateful widgets become more attractive. Many Flutter apps use utility packages like provider, which provides a wrapper around InheritedWidget. Flutter’s layered architecture also enables alternative approaches to implement the transformation of state into UI, such as the flutter_hooks package.
随着的增长,简化流程的方式:创建和使用stateful widget的更高级的状态管理方法变得越来越有吸引力。 许多Flutter app都使用provider之类的实用程序库,provider程序库封装了** InheritedWidget 。 Flutter的分层体系结构还启用了其他方法来实现将state转换为UI的方法,例如 flutter_hooks **程序库。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值