flutter08 - widget

Widget简介

概念

Flutter中几乎所有的对象都是一个Widget,Flutter中的Widget的概念更广泛,它不仅可以表示UI元素,也可以表示一些功能性的组件如:用于手势检测的 GestureDetector widget、用于APP主题数据传递的Theme等等,

widget与Element

  • Widget实际上就是Element的配置数据,Widget树实际上是一个配置树,而真正的UI渲染树是由Element构成;不过,由于Element是通过Widget生成的,所以它们之间有对应关系,在大多数场景,我们可以宽泛地认为Widget树就是指UI控件树或UI渲染树。
  • 一个Widget对象可以对应多个Element对象。这很好理解,根据同一份配置(Widget),可以创建多个实例(Element)。

Widget主要窗口

@immutable
abstract class Widget extends DiagnosticableTree {
  const Widget({ this.key });
  final Key key;

  @protected
  Element createElement();

  @override
  String toStringShort() {
    return key == null ? '$runtimeType' : '$runtimeType-$key';
  }

  @override
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
    properties.defaultDiagnosticsTreeStyle = DiagnosticsTreeStyle.dense;
  }

  static bool canUpdate(Widget oldWidget, Widget newWidget) {
    return oldWidget.runtimeType == newWidget.runtimeType
        && oldWidget.key == newWidget.key;
  }
}
  • Widget类继承自DiagnosticableTreeDiagnosticableTree即“诊断树”,主要作用是提供调试信息。
  • Key: 这个key属性类似于React/Vue中的key,主要的作用是决定是否在下一次build时复用旧的widget,决定的条件在canUpdate()方法中。
  • createElement():正如前文所述“一个Widget可以对应多个Element”;Flutter Framework在构建UI树时,会先调用此方法生成对应节点的Element对象。此方法是Flutter Framework隐式调用的,在我们开发过程中基本不会调用到。
  • debugFillProperties(...) 复写父类的方法,主要是设置诊断树的一些特性。
  • canUpdate(...)是一个静态方法,它主要用于在Widget树重新build时复用旧的widget,其实具体来说,应该是:是否用新的Widget对象去更新旧UI树上所对应的Element对象的配置;通过其源码我们可以看到,只要newWidgetoldWidgetruntimeTypekey同时相等时就会用newWidget去更新Element对象的配置,否则就会创建新的Element

StatelessWidget

作用:用于不需要维护状态的场景,它通常在build方法中通过嵌套其它Widget来构建UI,在构建过程中会递归的构建其嵌套的Widget。

继承自Widget类,重写了createElement()方法:

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

Context

context是BuildContext类的一个实例,表示当前widget在widget树中的上下文,每一个widget都会对应一个context对象(因为每一个widget都是widget树上的一个节点)。

StatefulWidget

StatefulWidget也是继承自Widget类,并重写了createElement()方法,不同的是返回的Element 对象并不相同;另外StatefulWidget类中添加了一个新的接口createState()

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生命周期

import 'package:flutter/material.dart';

void main() => runApp(CounterWidget(
      initValue: 10,
    ));

class CounterWidget extends StatefulWidget {
  final int initValue;

  const CounterWidget({Key key, this.initValue});

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

class _CounterWidgetState extends State<CounterWidget> {
  int _counter;


  /**
   * 第一次被调用
   */
  @override
  void initState() {
    super.initState();
    //初始化状态
    _counter = widget.initValue;
    print("生命周期:initState");
  }

  @override
  Widget build(BuildContext context) {
    print("生命周期:build");

    return MaterialApp(
      title: "计数器",
      home: Scaffold(
        appBar: AppBar(
          title: Text("计数器"),
        ),
        body: Center(
          child: FlatButton(
            child: Text("$_counter"),
            //点击后计数器自增
            onPressed: () => setState(() => ++_counter),
          ),
        ),
      ),
    );
  }

  //在新旧widget的key和runtimeType同时相等时didUpdateWidget()就会被调用
  @override
  void didUpdateWidget(CounterWidget oldWidget) {
    super.didUpdateWidget(oldWidget);
    print("生命周期:didUpdateWidget");
  }

  //state对象从树中被移除时调用
  @override
  void deactivate() {
    super.deactivate();
    print("生命周期:deactivate");
  }

  //state对象从树中被永久移除时调用
  //通常用来回收和释放资源
  @override
  void dispose() {
    super.dispose();
    print("生命周期:dispose");
  }

  //只有热重载时候会调用
  @override
  void reassemble() {
    super.reassemble();
    print("生命周期:reassemble");
  }

  //依赖对象发生变化时被调用
  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    print("生命周期:didChangeDependencies");
  }
}

在Widget树中获取State对象,并调用SnackBar的两种方式

import 'package:flutter/material.dart';

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

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "获取State对象",
      home: Scaffold(
        appBar: AppBar(
          title: Text("获取State对象"),
        ),
        body: GetState(),
      ),
    );
  }
}

class GetState extends StatefulWidget {
  @override
  _GetStateState createState() => _GetStateState();
}

class _GetStateState extends State<GetState> {
  @override
  Widget build(BuildContext context) {
    return Center(
        child: Column(
          children: <Widget>[
            Builder(
              builder: (context) {
                return RaisedButton(
                  onPressed: () {
                    // 查找父级最近的Scaffold对应的ScaffoldState对象
                    ScaffoldState _scaffoldState =
                    context.ancestorStateOfType(TypeMatcher<ScaffoldState>());
                    //调用ScaffoldState的showSnackBar来弹出SnackBar
                    _scaffoldState.showSnackBar(
                      SnackBar(
                        content: Text("我是SnackBar"),
                      ),
                    );
                  },
                  child: Text("点击显示SnackBar"),
                );
              },
            ),
            Builder(
              builder: (context) {
                return RaisedButton(
                  onPressed: () {
                    // 直接通过of静态方法来获取ScaffoldState
                    ScaffoldState _scaffoldState =
                    Scaffold.of(context);
                    //调用ScaffoldState的showSnackBar来弹出SnackBar
                    _scaffoldState.showSnackBar(
                      SnackBar(
                        content: Text("我是SnackBar"),
                      ),
                    );
                  },
                  child: Text("点击显示SnackBar"),
                );
              },
            ),
          ],
        )
    );
  }
}

通过GlobalKey来获取State对象

import 'package:flutter/material.dart';

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

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  //定义
  static GlobalKey<ScaffoldState> _globalKey = GlobalKey();

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "获取State对象",
      home: Scaffold(
        key: _globalKey, //设置key
        appBar: AppBar(
          title: Text("获取State对象"),
        ),
        body: Center(
            child: Column(
              children: <Widget>[
                Builder(
                  builder: (context) {
                    return RaisedButton(
                      onPressed: () {
                        // 查找父级最近的Scaffold对应的ScaffoldState对象

                        _globalKey.currentState.openDrawer();


                      },
                      child: Text("点击显示SnackBar"),
                    );
                  },
                ),
              ],
            )),
      ),
    );
  }
}
发布了49 篇原创文章 · 获赞 6 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/zlhyy666666/article/details/104895842