【Flutter -- 基础组件】Widget 简介

【Flutter -- 基础组件】Widget 简介_第1张图片

文章目录

    • 前言
    • Widget 简介
      • 1. StatelessWidget
      • 2. StatefulWidget

前言

上一篇,学习了 Dart 语法,对 Dart 的语法和特性有了更深一步的了解。今天,来学习 Flutter 的基础控件,身为 Android 开发者都知道,一开始入坑 Android 就要熟悉学习其控件,如:TextView,ImageView,Button,ListView,RecycleView 等。为什么要学习呢?因为平时的开发都离不开这些控件,UI 的呈现都是有这些控件组成的,因此,其重要性就不用说了。对于 Flutter 来讲,基础控件(widget)就更加重要了。Flutter 和 Android 有所不一样,Android 布局包含布局(RelativeLayout,LinearLayout,ConstrainLayou)和组件。Flutter的一切都是 Widget ,包括最顶层布局也是 Widget,一个页面有很多很多的 Widget 组合而成, Widget 也称为装饰品,窗口小部件。

在 Flutter 里,UI 控件就是 Widget ,Widget 根据不同的功能可以分为结构元素(如按钮或菜单),文本样式(字体或者颜色方案),布局属性(如填充,对齐,居中),可以这么理解,一个 flutter 的页面是有一棵树型的 Widget 组成,包括根节点,树枝和树叶,全都是 Widget ,只是 Widget 嵌套 Widget ,那就可以用下面这张图来表示:

【Flutter -- 基础组件】Widget 简介_第2张图片

Widget 简介

在 Flutter 中,Widget 是一切的基础,作为响应式渲染,属于 MVVM 的实现机制,通过修改数据,再用 setState 设置数据,Flutter 会自动通过绑定的数据更新 Widget ,所以在平时开发中,开发者需要的就是实现 Widget 界面,和数据绑定起来。在平时,用的最多就是 StatelessWidgetStatefulWidget 这两种 WidgetStatelessWidget 表示无状态的,StatefulWidget 表示有状态的。

这里怎么理解呢?

在 Flutter 中每个页面都是一帧,无状态就是保持在那一帧,总而言之就是不能跟用户交互,当有状态的 Widget 当数据更新时,其实是绘制了新的 Widget ,也就是 UI 发生了变化,只是 State 实现了跨帧数据同步保存。这里给大家说下,在 Android Studio 看源码的两个工具:

左边一栏 Structure 结构(看当前文件,win下的快捷键是(Alt+7))和右边 Hierarchy 继承关系(看当前类,win下快捷键是F4)都可以帮助你阅读源码。因为 StatelessWidgetStatefulWidget 用的最多,现在只需要用到这两个,就先学习这两个 Widget

1. StatelessWidget

StatelessWidget 只有三个方法:
【Flutter -- 基础组件】Widget 简介_第3张图片

  • const StatelessWidget({Key key}):super(key:key):初始化子类的 [key]。这个 key 类是Widget、Element、SemanticsNode唯一标识符,是用来控制 Widget 数中替换 Widget 的时候使用的。
  • StatelessElement createElement():创建一个[StatelessElement]来管理这个小部件在树中的位置,源码解释:子类重写此方法是不常见的,那这个方法也不用管,只需要知道这个方法用来管理自身在Widget树中的位置。
  • Widget build(BuildContext context):描述这部件呈现用户界面的部分。对于StatelessWidget,当 Widget 第一次插入到树中,或者父节点更改了配置和所依赖的[InheritedWidget]改变,都会被重新调用。

这里说下如何启动一个 Flutter 应用,并使用 Flutter 框架:

import 'package:flutter/material.dart';
void main() {
  return runApp(Widget app);
}

其实就是在main()函数中调用 runApp 函数。下面直接直接上例子,继承StatelessWidget,通过 build 方法返回一个控件:

import 'package:flutter/material.dart';
//使用`flutter/material.dart` 目的是使用Matrial风格的小控件
void main(){
  //运行程序
  runApp(MyApp(null));
}
//继承无状态的StatelessWidget 使程序自身变为Wiget
class MyApp extends StatelessWidget{

  //要显示的内容
  final String text;

  //数据内容可以通过构造方法传递进来
  MyApp(this.text);

  //重写build方法 返回你需要的控件
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Container(
      //红色背景
      color: Colors.red,
      //高度 现在没用 会撑满整个屏幕
      height: 200,
      //宽度 运行效果会撑满整个屏幕
      width: 200,
      //内容居中
      alignment: Alignment.center,
      //Text控件
      child: new Text(
          //Dart语法中 ?? 表示如果text为空,就会返回??号的内容
          text ?? "my name is Knight",
        textDirection: TextDirection.ltr,//需要加上这句不然报 RichText widgets require a Directionality widget ancestor.
      ),

    );
  }
}

WidgetWidget 之间通过 child 进行嵌套,有些 Widget 只能有一个 child。就像上面的 Container,有些 Widget 可以有多个child,像 Colum 布局。上面例子根布局是 ContainerContainer 嵌套了 Text

2. StatefulWidget

源码也是只有三个方法:
【Flutter -- 基础组件】Widget 简介_第4张图片
前两个方法和 StatelessWidget 一样的,而 createState() 这个方法源码注释是:在 Widget 树中给定的位置创建此可变状态的小部件,子类应该重写此方法返回新建的,关联子类的实例。当调用一个 StatefulWidget,框架就会调用createState这个方法,当一个 StatefulWidgetWidget 树中移除,再次插入树中,那么会再次调用 createState 来创建一个新的 State 对象,这样做简化了State对象的生命周期。

需要创建管理的是主要是 StateStatefulWidget 用起来麻烦一些,他需要一个 State,例子如下:

//继承StatefulWidget
class StateWidget extends StatefulWidget{
  
   @override
   State createState(){
     return _StateWidget();
   }
}

class _StateWidget extends State<StateWidget>{
  
  //重写build方法
  @override
  Widget build(BuildContext context){

  }
}

简单观察上面代码,大致流程还是和 StatelessWidget 一样的,build方法照样返回Widget,不过在StatefulWidget将这个方法放在createState里面。这里细想一下,也知道为什么要这样做,因为当状态改变,就会回调createState方法,重新调用build方法重新创建 UI,下面通过每两秒改变 UI 这个例子来加深理解:

import 'package:flutter/material.dart';
//使用`flutter/material.dart` 目的是使用Matrial风格的小控件
import 'dart:async';//记得导库
void main(){
  //运行程序
  runApp(StateWidget());
}
//控件继承State
class _StateWidget extends State<StateWidget>{
  int Number = 0;
  String text;
  //构造函数
  _StateWidget(this.text);

  @override
  void initState(){
    //初始化,这个函数在控件的生命周期内调用一次
    super.initState();
    print("进入initState");
    //3秒后改变text的内容
    new Future.delayed(const Duration(seconds: 3),(){
      setState(() {
        Number++;
        text = "已经改变数值,数值现在是$Number";
      });

    });
  }

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

  @override
  void didChangeDependencies(){
    //在initState之后调
     super.didChangeDependencies();
     print('进入didChange');
  }

  //重写build方法
  @override
  Widget build(BuildContext context){
    return Container(
      //红色背景
      color: Colors.red,
      //内容居中
      alignment: Alignment.center,
      //Text控件
      child: new Text(
        //Dart语法中 ?? 表示如果text为空,就会返回??号的内容
        text ?? "没改变数值",
        textDirection: TextDirection.ltr,//需要加上这句不然报 RichText widgets require a Directionality widget ancestor.
      ),

    );
  }
}

上面例子可以知道知道:在State可以动态更改数据,在调用setState后,改变的数据会除法Widget重新构建,上面代码还写了三个生命周期方法,这里简单说一下:

  • initState:初始化操作
  • didChangeDependencies:在initState之后调用,可以获取其他State
  • dispose:销毁

平时开发中在build实现布局的摆放,把数据添加Widget,通过setState改变数据。那如果很高频率取改变数据,性能肯定受影响,以下三点可以减少重新构建有状态控件的影响:

  1. 树根上尽量不用状态控件,因为如果数据有变化树根每次都更新,那就是整棵树都要重建,把状态用在树叶上,这样更新的时候只会更新自己。

  2. 减少build方法所创建的节点数量和控件数量。

  3. 利用缓存,如果子树中不更改,将子树中缓存起来,每次使用其子树时重新使用它,学会重用思想。

  4. 尽可能使用const修饰控件。怎么去选择有状态和无状态,最简单就是可以跟用户进行交互应该使用StatefulWidget,例如:点击,滑动屏幕信息流数据更新,如果只是仅仅显示数据,那就可以选择使用StatelessWidget创建一个无状态控件。

你可能感兴趣的:(Flutter,--,实战,flutter,android)