每日一题 Flutter#1 | 说说你对声明式 UI 的理解

最近在着手开发我的 《匠心星问》 ,它定位是一款 题库 应用,将集题目浏览、发布、解答、做题为一体。打算第一步先以 Flutter 为核心,准备题库资源。于是诞生《每日一题》 系列,准备精心设计一些 Flutter 的问题与解答,作为题库的养料。本文的焦点是探讨:

说说你对声明式 UI 的理解

声明式 UI 是现代前端开发的重要趋势,能显著提升效率和代码可维护性。理解其本质,有助于掌握 Flutter框架的设计理念,写出更简洁、易维护的代码,是成为优秀 Flutter 工程师的基础。

- -

前言

在移动端跨平台开发技术中,Flutter 无疑是近年来最受欢迎的框架之一。而它的核心理念之一,就是 声明式 UI(Declarative UI)。很多初学者在接触 Flutter 时,都会听到一句话:

Flutter 是一个声明式 UI 框架。

如今各个前端平台几乎都有了自己的声名式 UI 开发,比如

平台 框架
Android Jetpack Compose
iOS SwiftUI
鸿蒙 ArkUI
Web React、Vue
跨平台 Flutter、React Native 等

但声明式到底意味着什么?和命令式有什么不同?Flutter 是如何实现声明式 UI 的?这篇文章将结合个人理解,来聊一聊这个话题。


一、 什么是声明式 UI?

声明式 UI 的本质,是 描述你想要的界面样子 。而不是一步步命令 计算机如何构建它。

举个例子,假设要显示一段文本 张风捷特烈 ,并让它居中。在声明式 UI 中,可以是如下代码 :

dart 复制代码
@override
Widget build(BuildContext context) {
  return Center(
    child: Text('张风捷特烈'),
  );
}

你只需 声明 界面上应该有哪些组件(Text、Center),Flutter 框架负责把这段声明变成屏幕上的实际 UI。


而在命令式 UI(例如早期的 Android 原生开发)中,写法如下: 你必须手动创建组件,设置属性,然后放入布局中。

java 复制代码
TextView tv = new TextView(context);
tv.setText("张风捷特烈");
tv.setGravity(Gravity.CENTER);
layout.addView(tv);

总结一句话:

命令式 UI:告诉系统怎么做;

声明式 UI:告诉系统要什么。

打个比方: 假设你正在装修房子,你告诉装修工:

命令式的说法是:"先把这面墙粉刷白色,然后装上这扇门,之后在这放一个沙发......"

声明式的说法是:"我要一个现代简约风格的客厅,这里要有一个白色背景墙、一个深灰色沙发和一盏落地灯。"

前者是一些列的 动作指令集合 ,而后者是一系列的 描述数据集合 。总而言之,声明式 UI 让你专注 描述界面应该是什么样子 ,而不是 怎么把它一步步做出来


二、声明式 UI 的好处

声明式编程的最大好处就是 状态数据驱动界面更新 。Flutter 鼓励我们将 UI 视为状态的函数:

UI 是状态的函数: UI = f(state)

比如下面,当 isLoggedIn 状态改变时,调用重新构建的方法后,界面自动更新。我们控制组件的配置数据,无需控制其行为。

dart 复制代码
Widget build(BuildContext context) {
  return Text(isLoggedIn ? '欢迎回来' : '请先登录');
}

相比之下,命令式 UI 往往需要手动调用 setText()、invalidate()、notifyDataSetChanged() 等方法来刷新界面。声明式将有以下优势:

  • 更易维护: UI 界面由状态数据驱动,表现效果只需专注于数据内容。
  • 开发效率更高: 组件可拆分和组合,复用性高,构建界面像搭积木一样灵活。框架内部有高效的 diff 算法和局部刷新机制。
  • 更易测试和调试: 状态逻辑可单独测试,Widget 可进行快照测试(Widget Test)
  • 更好的语义性:组件属于界面的抽象描述,摆脱平台的差异,更易于阅读(前提是好的拆分)

三、声明式 UI 与界面更新

Flutter 界面是通过一个 Widget 树构建起来的。build 方法就像一个模板引擎,每次状态变化时都会重新执行这个方法,返回新的 Widget 树。其中 Widget 就是声名式 UI 中的描述信息。

dart 复制代码
@override
Widget build(BuildContext context) {
  return  Center(
    child: Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        const Text('You have pushed the button this many times:'),
        Text(
          '$_counter',
          style: Theme.of(context).textTheme.headlineMedium,
        ),
      ],
    ),
  ),
}

这个过程听起来像是每次都在重建 UI,其实 Flutter 并不是每次都 重绘 整个屏幕,它内部维护了三棵树:

  • Widget Tree:你写的代码
  • Element Tree:根据 Widget 生成的实际挂载的元素,支持 diff 比较
  • Render Tree:真正决定画面显示的节点

当 build() 被调用时,Flutter 会通过 diff 算法和标脏的机制,来高效地对比前后的 Widget 树,只更新必要的部分。因此,即便你频繁地调用 setState() 重建界面,Flutter 也能保持良好的性能。在下面的视频中介绍了连续 100 万次 setState 时,Flutter 的世界会发生什么:

《Flutter极限测试 - 连续 setState 1000000 次会怎么样?》


四、声明式 UI 的挑战

世上没有什么十全十美之物,得到了什么总得付出点什么。声明式 UI 也面临着一些挑战。

1. 状态管理复杂度上升

无论什么声名式 UI 框架,状态管理都是无法绕开的话题。毕竟 状态数据直接决定着界面的表现。虽然 UI = f(state) 简化了界面更新,但在大型项目中,状态本身就变得复杂:

  • 如何管理多个组件共享的状态?
  • 如何分析需求、拆分组件、整合逻辑
  • 初学者很容易将构建逻辑和业务逻辑耦合,容易代码混乱。
  • 在复杂状态管理下,如果处理不好,容易导致不必要的重建;

2.思维方式转换困难

传统 UI 开发者习惯了命令式思维,一步一步修改 UI ,切换到声明式范式需要脑回路重塑。开发者可能会陷入"build 重不重要?要不要缓存?这次 setState() 会不会引发不必要的刷新?" 等思维混乱。

  • 需要时间适应"状态驱动 UI"的思维;
  • 不熟悉新范式容易写出低效甚至错误的代码。
  • 对创建组件对象,容易产生顾虑,

3. 框架做的太多,自己知道的越少

Flutter 框架内部封装了很多内容,对初学者来说,内部的机制犹如黑箱,初期很难理解 build 的重建机制、 State 的生命周期回调。这些魔法般的表现,可能引起疑惑或者不确定性

  • 难以精确控制组件生命周期;
  • 副作用不易察觉,可能引发重复创建资源、内存泄漏等问题。

这些问题其实并不是声名式 UI 的问题,而是对工程化的经验把握、对 Flutter 框架的理解深度。这些都可以随着项目实践的深入得到缓解最后,我在这里给出这道题的简要回答,你有什么更好的见解,欢迎在评论区留言 ~

Q:说说你对声明式 UI 的理解

A: 声明式 UI 是指开发者只需描述在不同状态下界面应有的样子,框架会根据状态自动渲染 UI。与命令式 UI 不同,声明式 UI 不需要手动操作界面元素的增删改,而是通过状态数据驱动界面变化。Flutter、React 等都采用声明式 UI,优点是代码更简洁、易维护、易测试,缺点是对初学者理解有一定门槛。


更多文章和视频知识资讯,大家可以关注我的公众号、掘金和 B 站 。

相关推荐
安东尼肉店9 小时前
Android compose屏幕适配终极解决方案
android
2501_916007479 小时前
HTTPS 抓包乱码怎么办?原因剖析、排查步骤与实战工具对策(HTTPS 抓包乱码、gzipbrotli、TLS 解密、iOS 抓包)
android·ios·小程序·https·uni-app·iphone·webview
feiyangqingyun10 小时前
基于Qt和FFmpeg的安卓监控模拟器/手机摄像头模拟成onvif和28181设备
android·qt·ffmpeg
用户20187928316714 小时前
ANR之RenderThread不可中断睡眠state=D
android
煤球王子14 小时前
简单学:Android14中的Bluetooth—PBAP下载
android
小趴菜822715 小时前
安卓接入Max广告源
android
齊家治國平天下15 小时前
Android 14 系统 ANR (Application Not Responding) 深度分析与解决指南
android·anr
ZHANG13HAO15 小时前
Android 13.0 Framework 实现应用通知使用权默认开启的技术指南
android
【ql君】qlexcel15 小时前
Android 安卓RIL介绍
android·安卓·ril
写点啥呢15 小时前
android12解决非CarProperty接口深色模式设置后开机无法保持
android·车机·aosp·深色模式·座舱