Flutter开发之Widget

在Hello world中,我们发现flutter的嵌套挺多的,其实Flutter整个开发过程中就是形成一个Widget树,所以形成嵌套是很正常的。我们可以对我们的代码进行封装,将它们封装到自己的Widget中,创建自己的Widget。
在 Flutter 中,⼀切的显示都是 Widget 。Widget 是⼀切的基础,作为响应式的渲染,类似 MVVM 的实现机制。
我们可以通过修改数据,再⽤ setState 设置数据,Flutter 会⾃动通过绑定的数据更新 Widget 。 所以你需要做的就是实现 Widget 界⾯,并且和数据绑定起来
Widget 分为 有状态⽆状态 两种,在 Flutter 中每个⻚⾯都是⼀帧,⽆状态就是保持在那⼀帧,⽽有状态的 Widget 当数据更新时,其实是绘制了新的 Widget,只是 State 实现了跨帧的数据同步保 存。
总的来说就是,
StatelessWidget: 没有状态改变的Widget,通常这种Widget仅仅是做一些展示工作而已。
StatefulWidget: 需要保存状态,并且可能出现状态改变的Widget。
如何创建自己的Widget呢?
在Flutter开发中,我们可以继承自StatelessWidget或者StatefulWidget来创建自己的Widget类;

1、⽆状态StatelessWidget
StatelessWidget通常是一些没有状态(State,也可以理解成data)需要维护的Widget:
它们的数据通常是直接写死(放在Widget中的数据,必须被定义为final)

  • 从parent widget中传入的而且一旦传入就不可以修改;
  • 从InheritedWidget获取来使用的数据;

我们来看一下创建一个StatelessWidget的格式:

  1. 让自己创建的Widget继承自StatelessWidget;
  2. StatelessWidget包含一个必须重写的方法:build方法;
class MyStatelessWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return <返回我们的Widget要渲染的Widget,比如一个Text Widget>;
  }
}

build方法的解析:

Flutter在拿到我们自己创建的StatelessWidget时,就会执行它的build方法;

我们需要在build方法中告诉Flutter,我们的Widget希望渲染什么元素,比如一个Text Widget;

StatelessWidget没办法主动去执行build方法,当我们使用的数据发生改变时,build方法会被重新执行;

build方法什么情况下被执行呢?:

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

Widget 和 Widget 之间通过 child: 进⾏嵌套。其中有的 Widget 只能有⼀个 child,⽐如下⽅的Container ;有的 Widget 可以多个 child ,也就是 children: ,⽐如` Column 布局。下⽅代码便是 Container Widget 嵌套了 Text Widget。

main(List<String> args) {
  runApp(
      MaterialApp(
        home: Scaffold(
          appBar: AppBar(
            title: Text("Widget"),
          ),
          body: Center(
            child: DEMOWidget('Hello World'),
          ),
        ),
      )
  );
}

class DEMOWidget extends StatelessWidget {
  final String text;

//数据可以通过构造⽅法传递进来
  DEMOWidget(this.text);

  @override
  Widget build(BuildContext context) {
//这⾥返回你需要的控件
//这⾥末尾有没有的逗号,对于格式化代码⽽已是不⼀样的。
    return Container(
//⽩⾊背景
      color: Colors.white,
//Dart语法中,?? 表示如果text为空,就返回尾号后的内容。
      child: Text(text ?? "这就是⽆状态DMEO"),
    );
  }
}

在这里插入图片描述

2、有状态StatefulWidget
如下代码,是有状态的widget的简单实现。
你需要创建管理的是主要是 State通过 State 的 build ⽅法去构建控件。在 State 中,你可以动态改变数据这类似 MVVM 实现,在 setState 之后,改变的数据会触发 Widget 重新构建刷 新。⽽下⽅代码中,是通过延两秒之后,让⽂本显示为 “这就变了数值”
如下代码还可以看出,State 中主要的声明周期有 :
initState :初始化,理论上只有初始化⼀次
didChangeDependencies:在 initState 之后调⽤,此时可以获取其他 State 。
dispose :销毁,只会调⽤⼀次。

看到没,Flutter 其实就是这么简单!你的关注点只要在:创建你的 StatelessWidget 或者StatefulWidget ⽽已。你需要的就是在 build 中堆积你的布局,然后把数据添加到 Widget 中, 最后通过 setState 改变数据,从⽽实现画⾯变化。

import 'package:flutter/material.dart';
import 'dart:async';

main(List<String> args) {
  runApp(
      MaterialApp(
        home: Scaffold(
          appBar: AppBar(
            title: Text("Widget"),
          ),
          body: Center(
            child: DemoStateWidget('Hello World'),
          ),
        ),
      )
  );
}
class DemoStateWidget extends StatefulWidget { final String text;
通过构造⽅法传值
DemoStateWidget(this.text);

///主要是负责创建state @override
_DemoStateWidgetState createState() => _DemoStateWidgetState(text);
}

class _DemoStateWidgetState extends State<DemoStateWidget> {
  String text;
  _DemoStateWidgetState(this.text);

  @override
  void initState() {
    ///初始化,这个函数在⽣命周期中只调⽤⼀次super.initState();
    ///定时2秒
    ///
    new Future.delayed(const Duration(seconds: 1), () { 
      setState(() {
        text = "这就变了数值";
      });
    });
  }

  @override
  void dispose() {
    ///销毁super.dispose();
  }

  @override
  void didChangeDependencies() {
    ///在initState之后调 Called when a dependency of this [State] object changes. super.didChangeDependencies();
  }

  @override
  Widget build(BuildContext context) {
  return Container(
      child: Text(text ?? "这就是有状态DMEO"),
    );
  }
}

3、StatefulWidget生命周期

3.1. 生命周期的理解
什么是生命周期呢?

客户端开发:iOS开发中我们需要知道UIViewController从创建到销毁的整个过程,Android开发中我们需要知道Activity从创建到销毁的整个过程。以便在不同的生命周期方法中完成不同的操作; 前端开发中:Vue、React开发中组件也都有自己的生命周期,在不同的生命周期中我们可以做不同的操作;

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

StatefulWidget本身由两个类组成的:StatefulWidgetState
首先,执行StatefulWidget中相关的方法:

  1. 首先执行StatefulWidget的构造函数(Constructor)来创建出StatefulWidget;
  2. 执行StatefulWidget的createState方法,来创建一个维护StatefulWidget的State对象;
    其次,调用createState创建State对象时,执行State类的相关方法:
    • 执行State类的构造方法(Constructor)来创建State对象;
    • 执行initState,我们通常会在这个方法中执行一些数据初始化操作,或者也可能会发送网络请求。
  3. 执行didChangeDependencies方法,这个方法在两种情况下会调用:
    • 调用initState会调用
    • 从其他对象中依赖一些数据发生改变时
  4. Flutter执行build方法,来看一下我们当前的Widget需要渲染哪些Widget;
  5. 当前的Widget不再使用时,会调用dispose进行销毁;
  6. 手动调用setState方法,会根据最新的状态(数据)来重新调用build方法,构建对应的Widgets;
  7. 执行didUpdateWidget方法是在当父Widget触发重建(rebuild)时,系统会调用didUpdateWidget方法;

具体通过代码


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方法
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值