美文网首页Flutter学习笔记
Flutter-StatelessWidget和Stateful

Flutter-StatelessWidget和Stateful

作者: WinJayQ | 来源:发表于2020-04-18 17:05 被阅读0次

1. StatelessWidget

1.1 StatelessWidget通常是一些没有状态(State,也可以理解成data)需要维护的Widget:

  • 它们的数据通常是直接写死;
  • 从parent widget中传入的而且一旦传入就不可以修改;
  • 从InheritedWidget获取来使用的数据;

1.2 StatelessWidget包含一个必须重写的方法:build方法;

StatelessWidget没办法主动去执行build方法,当我们使用的数据发生改变时,build方法会被重新执行
build方法什么情况下被执行呢?:

  • 1)当我们的StatelessWidget第一次被插入到Widget树中时(也就是第一次被创建时);
  • 2)当我们的父Widget(parent widget)发生改变时,子Widget会被重新构建;
  • 3)如果我们的Widget依赖InheritedWidget的一些数据,InheritedWidget数据发生改变时;

2.有状态的StatefulWidget

2.1 Flutter如何做到我们在开发中定义到Widget中的数据一定是final的呢?

@immutable
abstract class Widget extends DiagnosticableTree {
  const Widget({ this.key });
...省略代码...
}

这里有一个很关键的东西@immutable

  • 我们似乎在Dart中没有见过这种语法,这实际上是一个 注解,这涉及到Dart的元编程;
    官方有对@immutable进行说明:
  • 来源: https://api.flutter.dev/flutter/meta/immutable-constant.html
  • 说明: 被@immutable注解标明的类或者子类都必须是不可变的

结论: 定义到Widget中的数据一定是不可变的,需要使用final来修饰

2.2 如何存储Widget状态?

1)既然Widget是不可变,那么StatefulWidget如何来存储可变的状态呢?

  • StatelessWidget无所谓,因为它里面的数据通常是直接定义完后就不修改的。
  • 但StatefulWidget需要有状态(可以理解成变量)的改变,这如何做到呢?

2)Flutter将StatefulWidget设计成了两个类:

  • 也就是你创建StatefulWidget时必须创建两个类:
  • 一个类继承自StatefulWidget,作为Widget树的一部分;
  • 一个类继承自State,用于记录StatefulWidget会变化的状态,并且根据状态的变化,构建出新的Widget;

3)创建一个StatefulWidget,我们通常会按照如下格式来做:

  • 当Flutter在构建Widget Tree时,会获取State的实例,并且它调用build方法去获取StatefulWidget希望构建的Widget;
  • 那么,我们就可以将需要保存的状态保存在MyState中,因为它是可变的;
class MyStatefulWidget extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    // 将创建的State返回
    return MyState();
  }
}

class MyState extends State<MyStatefulWidget> {
  @override
  Widget build(BuildContext context) {
    return <构建自己的Widget>;
  }
}

2.3 思考:为什么Flutter要这样设计呢?

这是因为在Flutter中,只要数据改变了Widget就需要重新构建(rebuild)

2.4 StatefulWidget生命周期

1)Flutter小部件的生命周期:

  • StatelessWidget可以由父Widget直接传入值,调用build方法来构建,整个过程非常简单;
  • 而StatefulWidget需要通过State来管理其数据,并且还要监控状态的改变决定是否重新build整个Widget;
  • 所以,我们主要讨论StatefulWidget的生命周期,也就是它从创建到销毁的整个过程;

2)那么StatefulWidget有哪些生命周期的回调呢?它们分别在什么情况下执行呢?

  • 在下图中,灰色部分的内容是Flutter内部操作的,我们并不需要手动去设置它们;
  • 白色部分表示我们可以去监听到或者可以手动调用的方法;


    image.png
import 'package:flutter/material.dart';

main(List<String> args) {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text("HelloWorld"),
        ),
        body: HomeBody(),
      ),
    );
  }
}


class HomeBody extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    print("HomeBody build");
    return MyCounterWidget();
  }
}


class MyCounterWidget extends StatefulWidget {
  
  MyCounterWidget() {
    print("执行了MyCounterWidget的构造方法");
  }
  
  @override
  State<StatefulWidget> createState() {
    print("执行了MyCounterWidget的createState方法");
    // 将创建的State返回
    return MyCounterState();
  }
}

class MyCounterState extends State<MyCounterWidget> {
  int counter = 0;
  
  MyCounterState() {
    print("执行MyCounterState的构造方法");
  }

  @override
  void initState() {
    super.initState();
    print("执行MyCounterState的init方法");
  }
  
  @override
  void didChangeDependencies() {
    // TODO: implement didChangeDependencies
    super.didChangeDependencies();
    print("执行MyCounterState的didChangeDependencies方法");
  }

  @override
  Widget build(BuildContext context) {
    print("执行执行MyCounterState的build方法");
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              RaisedButton(
                color: Colors.redAccent,
                child: Text("+1", style: TextStyle(fontSize: 18, color: Colors.white),),
                onPressed: () {
                  setState(() {
                    counter++;
                  });
                },
              ),
              RaisedButton(
                color: Colors.orangeAccent,
                child: Text("-1", style: TextStyle(fontSize: 18, color: Colors.white),),
                onPressed: () {
                  setState(() {
                    counter--;
                  });
                },
              )
            ],
          ),
          Text("当前计数:$counter", style: TextStyle(fontSize: 30),)
        ],
      ),
    );
  }

  @override
  void didUpdateWidget(MyCounterWidget oldWidget) {
    super.didUpdateWidget(oldWidget);
    print("执行MyCounterState的didUpdateWidget方法");
  }

  @override
  void dispose() {
    super.dispose();
    print("执行MyCounterState的dispose方法");
  }
}

打印结果如下:

flutter: HomeBody build
flutter: 执行了MyCounterWidget的构造方法
flutter: 执行了MyCounterWidget的createState方法
flutter: 执行MyCounterState的构造方法
flutter: 执行MyCounterState的init方法
flutter: 执行MyCounterState的didChangeDependencies方法
flutter: 执行执行MyCounterState的build方法

// 注意:Flutter会build所有的组件两次(查了GitHub、Stack Overflow,目前没查到原因)
flutter: HomeBody build
flutter: 执行了MyCounterWidget的构造方法
flutter: 执行MyCounterState的didUpdateWidget方法
flutter: 执行执行MyCounterState的build方法

当我们改变状态,手动执行setState方法后会

flutter: 执行执行MyCounterState的build方法

学习内容来自Flutter从入门到实战

相关文章

网友评论

    本文标题:Flutter-StatelessWidget和Stateful

    本文链接:https://www.haomeiwen.com/subject/eocsvhtx.html