Flutter basic components: Widget Introduction

concept

Flutter in almost all objects are a Widget. And Native Development in the "Controls" The difference is that the concept of Widget Flutter wider, it can not only represent UI elements, may also represent some of the functional components such as: GestureDetector widget for gesture detection for APP theme data Theme delivery, etc., and the development of native controls typically refers only to UI elements.

Widget and Element

In the Flutter, Widget function is to "describe the configuration data of a UI element," which is to say, Widget is not really represent the final display elements drawn on the device screen, and it describes a configuration data element.
In fact, Flutter is displayed on the screen truly represents the earth element is Element, that is just Widget configuration data describing the Element! UI Widget just one configuration data elements, and may correspond to a plurality of Widget Element. This is because the same Widget objects can be added to different parts of the UI tree, and the real rendering, UI Element tree every node will correspond to a Widget object.

to sum up:

  1. Widget actually Element configuration data, Widget configuration tree is actually a tree, while the real UI rendering tree is made Element; however, since the Element is generated by Widget, so there is a correspondence between them, the most scene, we can think broadly refers Widget tree UI UI rendering control tree or tree.
  2. Widget object may correspond to a plurality of Element object. This is well understood, in accordance with a configuration (Widget), you can create multiple instances (Element).

StatelessWidget

StatelessWidget scene does not need to maintain state, which is usually constructed by a nested UI Widget other in the build process, will build during the build process of the Widget nested recursive.

import 'package:flutter/material.dart';

class Echo extends StatelessWidget {
  const Echo({
    Key key,
    @required this.text, this.backgroundColor:Colors.red,
  }):super(key:key);

  final String text;
  final Color backgroundColor;

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        color: backgroundColor,
        child: Text(text),
      ),
    );
  }

}

// 按照惯例,widget的构造函数参数应使用命名参数,命名参数中的必要参数要添加@required标注,这样有利于静态代码分析器进行检查。
// 另外,在继承widget时,第一个参数通常应该是Key,另外,如果Widget需要接收子Widget,那么child或children参数通常应被放在参数列表的最后。
// 同样是按照惯例,Widget的属性应尽可能的被声明为final,防止被意外改变。

Context

build () method has a context parameter, which is an instance of class BuildContext representing the current context widget in the widget tree, each corresponding to a widget will be a context object (widget is a widget because each node of a tree). Indeed, context is the current widget performs "related operation" in the position to handle a widget tree, such that a current provided from the widget tree traversing widget and a method to find the parent of the widget according to widget type upward.

import 'package:flutter/material.dart';

class TestContextRoute extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Test Context'),
      ),
      body: Container(
        child: Builder(builder: (context){
          // 在Widget树中向上查找父级‘Scaffold’ widget
          Scaffold scaffold = context.ancestorWidgetOfExactType(Scaffold);
          // 直接返回 AppBar的title
          return (scaffold.appBar as AppBar).title;
        }),
      ),
    );
  }
}

StatefulWidget

Like and StatelessWidget, StatefulWidget is inherited from the Widget class, and rewriting the createElement () method, the difference is not the same as Element object returned; StatefulWidget further adds a new class interface createState ()

// StatefulWidget的类定义:
import 'package:flutter/material.dart';

abstract class StatefulWidget extends Widget {
  const StatefulWidget({ Key key }) : super(key: key);

  @override
  StatefulElement createElement() => new StatefulElement(this);

  @protected
  State createState();
}

// StatefulElement 间接继承自Element类,与StatefulWidget相对应(作为其配置数据)。
// StatefulElement中可能会多次调用createState()来创建状态(State)对象。

// createState() 用于创建和Stateful widget相关的状态,它在Stateful widget的生命周期中可能会被多次调用。
// 例如,当一个Stateful widget同时插入到widget树的多个位置时,Flutter framework就会调用该方法为每一个位置生成一个独立的State实例,
// 其实,本质上就是一个StatefulElement对应一个State实例。

State

A StatefulWidget class will correspond to a class State, State represents the state of the corresponding StatefulWidget to maintain the status information stored in the State can be:

  1. Synchronization can be read when constructing widget.
  2. Widget can be changed in the life cycle, when the State is changed, which can be invoked manually setState () method changes the state notification Flutter framework,
    Flutter framework after receiving the message, which will be called again build method rebuild widget tree to the purpose of updating the UI.

State There are two common properties:

  1. widget, widget instance which represents State associated with that instance, provided by a dynamic Flutter framework.
    Note that this association is not permanent, because the application lifecycle, widget instances of a node of a tree UI may change when rebuilt,
    but the State will only be created when the instance is first inserted into the tree , when reconstructed, if the widget is changed, Flutter framework to dynamically set State.widget new widget instance.
  2. context. StatefulWidget corresponding BuildContext, StatelessWidget the same effect BuildContext.
// State的生命周期
// 实现一个计数器widget,点击它可以使计数器加1,由于要保存计数器的数值状态,所以我们应继承StatefulWidget
import 'package:flutter/material.dart';


// CounterWidget接收一个initValue整型参数,它表示计数器的初始值
class CounterWidget extends StatefulWidget {
  const CounterWidget({Key key, this.initValue: 0});

  final int initValue;

  @override
  _CounterWidgetState createState() => _CounterWidgetState();
}


//
class _CounterWidgetState extends State<CounterWidget> {
  int _counter;

  // 当Widget第一次插入到Widget树时会被调用,对于每一个State对象,Flutter framework只会调用一次该回调,
  // 所以,通常在该回调中做一些一次性的操作,如状态初始化、订阅子树的事件通知等。
  // 不能在该回调中调用BuildContext.inheritFromWidgetOfExactType(该方法用于在Widget树上获取离当前widget最近的一个父级InheritFromWidget,关于InheritedWidget我们将在后面章节介绍),
  // 原因是在初始化完成后,Widget树中的InheritFromWidget也可能会发生变化,所以正确的做法应该在在build()方法或didChangeDependencies()中调用它。
  @override
  void initState(){
    super.initState();
    // 初始化状态
    _counter = widget.initValue;
    print('initState');
  }

  // 主要是用于构建Widget子树的,会在如下场景被调用:
  // 1. 在调用initState()之后。
  // 2. 在调用didUpdateWidget()之后。
  // 3. 在调用setState()之后。
  // 4. 在调用didChangeDependencies()之后。
  // 5. 在State对象从树中一个位置移除后(会调用deactivate)又重新插入到树的其它位置之后。
  @override
  Widget build(BuildContext context) {
    print('build');
    return Scaffold(
      appBar: AppBar(
        title: Text('Test State'),
      ),
      body: Center(
        child: FlatButton(
          child: Text('$_counter'),
          // 点击后计数器自增
          onPressed: ()=>setState(()=>++_counter),
        ),
      ),
    );
  }

  // 在widget重新构建时,Flutter framework会调用Widget.canUpdate来检测Widget树中同一位置的新旧节点,然后决定是否需要更新,如果Widget.canUpdate返回true则会调用此回调。
  // 正如之前所述,Widget.canUpdate会在新旧widget的key和runtimeType同时相等时会返回true,也就是说在在新旧widget的key和runtimeType同时相等时didUpdateWidget()就会被调用。
  @override
  void didUpdateWidget(CounterWidget oldWidget) {
    super.didUpdateWidget(oldWidget);
    print('didUpdateWidget');
  }

  // 当State对象从树中被移除时,会调用此回调。
  // 在一些场景下,Flutter framework会将State对象重新插到树中,如包含此State对象的子树在树的一个位置移动到另一个位置时(可以通过GlobalKey来实现)。
  // 如果移除后没有重新插入到树中则紧接着会调用dispose()方法。
  @override
  void deactivate() {
    super.deactivate();
    print('deactivate');
  }

  // 当State对象从树中被永久移除时调用。通常在此回调中释放资源。
  @override
  void dispose() {
    super.dispose();
    print('dispose');
  }

  // 此回调是专门为了开发调试而提供的,在热重载(hot reload)时会被调用,此回调在Release模式下永远不会被调用。
  @override
  void reassemble() {
    super.reassemble();
    print("reassemble");
  }

  // 当State对象的依赖发生变化时会被调用;
  // 例如:在之前build()中包含了一个InheritedWidget,然后在之后的build()中InheritedWidget发生了变化,那么此时InheritedWidget的子widget的didChangeDependencies()回调都会被调用。
  // 典型的场景是当系统语言Locale或应用主题改变时,Flutter framework会通知widget调用此回调。
  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    print("didChangeDependencies");
  }

}

Very important analysis:

  1. Run the application and open the route page after page open new routes, center of the screen there will be a number 0, the console log output:
    the I / Flutter (22202): InitState
    the I / Flutter (22202): didChangeDependencies
    the I / Flutter (22202 ): build
    can be seen, when inserted into the StatefulWidget Widget tree method is called first initState

  2. Click thermal overload button, the console log output:
    the I / Flutter (22202): reassemble
    the I / Flutter (22202): didUpdateWidget
    the I / Flutter (22202): Build
    seen, and this time initState didChangeDependencies have not been called, and At this point it is called didUpdateWidget

  3. Removing the widget tree CountWidget, the route to
    RaisedButton (
    Child: the Text ( 'the Test State'),
    textColor: Colors.blue,
    onPressed: () {
    Print ( 'Test State');
    // Navigator.pushNamed (context, 'Test State');
    },
    then thermally overloaded, the console log output:
    the I / Flutter (22202): reassemble
    the I / Flutter (22202): the deactivate
    the I / Flutter (22202): Dispose
    can be seen, from the widget CounterWidget the tree is removed, deactivate and dispose in turn be called

StatefulWidget life cycle

As shown below:
StatefulWidget life cycle

Guess you like

Origin www.cnblogs.com/parzulpan/p/12056387.html
Recommended