Flutter中文网

Flutter中文网

Flutter核心原理之UI框架(Framework)

38
2024-07-28

UI框架是什么

Flutter 主要由三层组成:框架层、引擎层和嵌入层。开发者主要与框架层进行交互。本文将深入探讨 Flutter 框架层的工作机制。然而,在深入讨论之前,我们应先理解更一般的UI框架是指什么,以及它是如何解决问题的。

一般来说,UI框架(UI Framework)是指那些针对某个特定的平台,以帮助快速开发图形用户界面(GUI)为目的所实现的框架。这里的平台通常是指操作系统或浏览器。通常情况下,平台只能提供最基础的图形API,如创建线条、几何图形等。在大多数平台上,这些基础的图形API通常被封装在了一个Canvas对象中进行中心化管理。试想如果没有UI框架的帮助,而是直接使用Canvas来构建用户界面将会是如何困难且低效!因此,简而言之,UI框架的主要任务就是:如何基于这些基础的图形API,比如 Canvas, 构建一个可以高效创建UI的框架。

我们知道,无论是在 Android 还是 iOS 平台,UI 框架工作的原理都是类似的,也就是说,它们在将一个用户界面呈现到屏幕的过程中,使用的流程是基本相同的。因此,在我们深入讨论Flutter UI框架前,先让我们理解一下平台的图形处理基本原理,这将有助于更清晰地理解操作系统和系统底层UI的逻辑。

硬件绘图基本原理

当我们谈论原理时,我们首先要理解屏幕是如何显示图像的。显示器(或者说屏幕)是由众多的物理显示单元组成,而每一个单元都可以被视为一个物理像素点。每一个像素点可以展现出各种颜色,图像显示的基本机制就是在不同的物理像素点上呈现出不同的颜色,以此形成完整的图像。

设备像素点能够发出的颜色总数是判断显示器质量的关键指标。例如,当我们提到1600万色显示器时,其实就是指一个像素点可以显示出1600万种颜色。显示器颜色是通过组合RGB三原色来形成的。因此,1600万色其实就是2的24次方的结果,表示每一种原色(红、绿、蓝)都有8位深度。颜色深度越大,显示的色彩越丰富绚烂。

为了更新渲染的画面,显示器会以固定频率获取GPU的数据进行刷新,例如,一部手机屏幕的刷新频率可能为60Hz。当一帧图像完全绘制完毕,且准备开始绘制下一帧时,显示器会发出一个垂直同步信号(例如vsync)。屏幕在每一秒内将会发出60次此类信号。这个信号主要用来同步 CPU、GPU和显示器之间的工作进度。通常,计算机系统中的CPU、GPU和显示器配合工作:CPU担当内容计算并将结果提交给GPU,GPU渲染这些内容并放入帧缓冲区,之后视频控制器将根据同步信号从帧缓冲区抓取帧数据并传输给显示器显示。

CPU和GPU分别负责不同类型的任务。CPU主要用于基础的数学和逻辑计算,而GPU则负责执行与图形处理相关的复杂的数学运算,如矩阵变换和几何计算。GPU的主要作用是联合计算并确定最终传输至显示器显示的每个像素点的颜色值。

系统图形绘制API的封装过程

所有的图形计算和渲染,实际上最后都是由相应的硬件来完成的。然而,操作系统通常会屏蔽直接操作硬件的指令,因此应用开发者通常不会直接面向硬件进行操作。操作系统将这些底层硬件操作隐藏后,会提供一组封装过的API供应用进行调用。然而,对于应用开发者来说,直接使用这些由操作系统提供的API通常是相当复杂且低效的。因为这些API通常都是非常基础的,如果要直接调用,开发者需要深入了解 API 的细节。

出于这个原因,几乎所有的GUI应用开发编程语言都会在操作系统之上再封装一层。这样,操作系统原生的API就会被封装在一个编程框架和模型中,并定义一套简单的开发规则。这使得开发者可以更方便地开发GUI应用程序。这个额外的封装层,就是我们常说的 "UI框架"。比如,Android SDK实际上封装了Android操作系统的API,并提供了一个以“UI描述文件XML+Java/Kotlin操作DOM”形式的UI框架。类似的,.iOS的UIKit也对View进行了抽象。这类框架会将操作系统API抽象成一种基础对象(如用于2D图形绘制的Canvas),然后定义了一套规则来描述UI,比如UI树结构和UI操作的单线程原则等。

理解 Flutter UI 框架

从我们的讨论中可以看出,无论是 Android SDK 还是 iOS 的 UIKit,其职责都是一致的,只是因为语言和底层系统的不同而已。那么,是否可能创建这样的一个 UI 框架:采用统一的编程语言来开发,针对不同的操作系统 API 构建一个面向上层接口一致、但针对下层各个操作系统进行特定适配的中间层,然后在打包编译的时候根据需要选择中间层代码?如果这可以办到,我们就能够用同样的代码创建跨平台应用。Flutter的工作原理就是这样的,它提供了一组 Dart API,然后在底层通过 OpenGL 这种跨平台的绘制库(内部会调用操作系统 API),实现一套代码跨多平台的工作。由于其内部的 Dart API 也是调用操作系统 API,所以它的性能接近原生。有两点值得注意:

  1. 尽管 Dart 先调用了 OpenGL,然后OpenGL再调用操作系统API,但这仍被视为原生渲染。因为 OpenGL 仅仅是对操作系统API的一个封装库,它并不像 WebView 渲染那样需要 JavaScript 运行环境和 CSS 渲染器,因而不会有性能损失。

  2. 在 Flutter 的早期版本中,底层采用了 OpenGL 这样的跨平台库。但在 iOS 设备上,苹果提供了专门的图形库 Metal,使用 Metal 在 iOS 设备上性能超过 OpenGL,因此,后续的 Flutter 在 iOS 设备上优先使用 Metal,只在 Metal 不可用时才降级使用 OpenGL。然而,无论 Flutter 底层调用的是哪个库,作为应用开发者,我们并不需要过于关心,只需了解其调用了原生的绘图接口,可以保证高性能即可。

到这里,我们已经探讨了 Flutter UI 框架与操作系统交互这一部分的原理,现在我们需要探讨一下它为应用开发者定义的开发规范。简而言之,规范核心在于 "组合" 和 "响应式"。要开发一个 UI 界面,需要通过组合其他 Widget 来实现。在 Flutter 中,万物皆 Widget。当 UI 需要变动时,我们并不直接修改 DOM,而是通过更新状态,让 Flutter UI 框架根据新的状态重新构建 UI。

至此,你可能已经注意到 Flutter UI 框架 和 Flutter Framework 概念上有很大相似性,实际上,这是确切的。之所以称之为 "UI 框架",是因为在其他平台中可能没有这样的叫法,在这里,我们只是为了统一概念便于讨论,因此,不必过于纠结于具体的概念。