flutter:Widget类与State类中的widget

  1. Widget 是什么
  2. State类中的widget
    1. 是什么

Widget 是什么

在 Flutter 中,Widget 是 UI 的配置(configuration)

  • 它本身 不是真正的显示元素(不是按钮、不是图片、不是文字)。

  • 它只是描述了界面长什么样子、需要哪些参数。

  • 真正显示在屏幕上的东西是 Element(Flutter 内部类)和底层的 RenderObject

Widget 就像 蓝图Element 就像 工地上的工人RenderObject 就是最终建好的 房子

在 Flutter SDK 里的源码如下(省略):

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

  final Key? key;

  @protected
  Element createElement();
}
  • @immutable:Widget 必须是不可变的(Immutable)。意思是:你不能直接修改 Widget 的属性,只能通过创建一个新的 Widget 来替换。

  • key:用来标识 Widget,帮助框架在重建时决定是复用旧的 Element,还是销毁重建。

  • createElement():每个 Widget 会创建一个对应的 Element,用来挂到 Flutter 的 Element Tree 上。

  • 举例说明:

    Text("Hello", style: TextStyle(fontSize: 20))
    
    • Text Widget 只是一个配置:要显示字符串 "Hello",字体大小 20。
    • Flutter 内部会调用 Text.createElement(),创建一个 Element 节点,挂到 Element 树上。
    • Element 会再创建对应的 RenderObject,它才是真正在屏幕上绘制文字的对象。

所有 Flutter UI 都是由 Widget 构成的,常见有三大类:

  • StatelessWidget:没有内部状态,完全由构造函数参数决定。例如:Text("Hello")Icon(Icons.add)

  • StatefulWidget:有内部可变状态,需要搭配一个 State 来维护。例如:CheckboxTextField、你写的 ImageWidget

  • InheritedWidget:用于在 Widget 树中向下传递数据,常用于全局状态共享(比如 Theme.of(context))。

State类中的widget

import 'package:cached_network_image/cached_network_image.dart';
import 'package:ducafe_ui_core/ducafe_ui_core.dart';
import 'package:flutter/material.dart';
import '../index.dart';
import 'package:flutter_svg/svg.dart';

/// 图片类型
enum ImageWidgetType {
  img,
  svg,
  svgRaw,
}

/// 图片组件
class ImageWidget extends StatefulWidget {
  const ImageWidget({
    super.key,
    required this.path,
    required this.type,
    this.radius,
    this.width,
    this.height,
    this.fit,
    this.placeholder,
    this.errorWidget,
    this.elevation,
    this.color,
  });

  /// 文件路径
  final String path;

  /// 类型
  final ImageWidgetType type;

  /// 圆角
  final double? radius;

  /// 宽度
  final double? width;

  /// 高度
  final double? height;

  /// 自适应方式
  final BoxFit? fit;

  /// 占位图
  final Widget? placeholder;

  /// 错误图
  final Widget? errorWidget;

  /// 阴影
  final double? elevation;

  /// 颜色
  final Color? color;

  const ImageWidget.img(
    this.path, {
    super.key,
    this.radius,
    this.width,
    this.height,
    this.fit,
    this.placeholder,
    this.errorWidget,
    this.elevation,
    this.color,
  }) : type = ImageWidgetType.img;


  @override
  State<ImageWidget> createState() => _ImageWidgetState();
}

class _ImageWidgetState extends State<ImageWidget> {
  Widget _buildView() {
    Widget ws = widget.placeholder ?? const SizedBox();

    // 是否是网络图片
    bool isNetwork = widget.path.startsWith('http') ||
        widget.path.startsWith('https') ||
        widget.path.startsWith('//');

    // 1 图片

    // asset 图片
    if (widget.type == ImageWidgetType.img && !isNetwork) {
      ws = Image.asset(
        widget.path,
        fit: widget.fit,
        color: widget.color,
      );
    }

    // 网络图片
    else if (widget.type == ImageWidgetType.img && isNetwork) {
      ws = CachedNetworkImage(
        imageUrl: widget.path,
        fit: widget.fit,
        cacheKey: widget.path.hashCode.toString(),
        color: widget.color,
        placeholder: (context, url) =>
            widget.placeholder ??
            const CircularProgressIndicator()
                .tightSize(AppSize.indicator)
                .center(),
        errorWidget: (context, url, error) =>
            widget.errorWidget ?? const Icon(Icons.error),
      );
    }

    return ws;
  }

  @override
  Widget build(BuildContext context) {
    return _buildView();
  }
}

是什么

abstract class State<T extends StatefulWidget> with Diagnosticable {
  T get widget => _widget!;
  T? _widget;
}
  • widget 是一个 getter,返回 _widget

  • _widget 在框架内部由 Flutter 赋值,它保存着当前和 State 绑定的 StatefulWidget 实例

  • 换句话说: widget 就是你在外面创建的 StatefulWidget 对象。

class ImageWidget extends StatefulWidget {
  //----------------------中间省略代码--------------------------
  @override
  State<ImageWidget> createState() => _ImageWidgetState();
}
class _ImageWidgetState extends State<ImageWidget> {
  //----------------------中间省略代码--------------------------
  @override
  Widget build(BuildContext context) {
    return _buildView();
  }
}
  • Flutter 框架规定:每个 StatefulWidget 必须实现createState()方法。比如上面的案例:ImageWidget 创建出来时,Flutter 框架会调用 createState() 来生成一个 _ImageWidgetState 实例。之后,Flutter 会把这个 StateWidget 绑定在一起。

  • _ImageWidgetState 里,widget 指向的就是这个 ImageWidget 实例。 ImageWidget 实例里面有什么属性和方法,widget也会拥有同样的属性和方法。

    // 如果 ImageWidget 创建了一个这样的实例
    ImageWidget(
      path: "http://xxx.png",
      radius: 8,
    )
    // 如果我 _ImageWidgetState 里面使用 widget.xxx,其实就是在访问xxx的属性
    widget.path     // "http://xxx.png"
    widget.radius   // 8
    

widget 的生命周期:Flutter 框架会自动维护 widget 的赋值:

  • 第一次创建:调用 createState() 时,Flutter 会把 ImageWidget 实例赋给 _ImageWidgetState._widget

  • 热重建 / 父组件更新时:Flutter 会调用 didUpdateWidget(oldWidget),然后更新 _widget 的值。这样 State 始终持有最新的 widget

  • State 是持久的(不会轻易销毁),但 widget 会不断被新实例替换。

×

喜欢就点赞,疼爱就打赏