# Flutter UI系統
在本書的前面章節中,我們多次提到"UI系統"這個概念,本書中所指的UI系統特指:基于一個平臺,在此平臺上實現GUI的一個系統,這里的平臺特指操作系統,如Android、iOS或者Windows、macOS。我們說過各個平臺UI系統的原理是相通的,也就是說無論是Android還是iOS,他們將一個用戶界面展示到屏幕的流程是相似的,所以,在介紹Flutter UI系統之前,我們先看看UI系統的基本原理,這樣可以幫助讀者對操作系統和系統底層UI邏輯有一個清晰的認識。
## UI系統原理
### 硬件繪圖基本原理
提到原理,我們要從屏幕顯示圖像的基本原理談起。我們知道顯示器(屏幕)是由一個個物理顯示單元組成,每一個單元我們可以稱之為一個物理像素點,而每一個像素點可以發出多種顏色,顯示器成相的原理就是在不同的物理像素點上顯示不同的顏色,最終構成完整的圖像。
一個像素點能發出的所有顏色總數是顯示器的一個重要指標,比如我們所說的1600萬色的屏幕就是指一個像素點可以顯示出1600萬種顏色,而顯示器顏色是有RGB三基色組成,所以1600萬即2的24次方,即每個基本色(R、G、B)深度擴展至8 bit(位),顏色深度越深,所能顯示的色彩更加豐富靚麗。
為了更新顯示畫面,顯示器是以固定的頻率刷新(從GPU取數據),比如有一部手機屏幕的刷新頻率是 60Hz。當一幀圖像繪制完畢后準備繪制下一幀時,顯示器會發出一個垂直同步信號(如VSync), 60Hz的屏幕就會一秒內發出 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操作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,所以它的性能接近原生。
> 注意,雖然Dart是先調用了OpenGL,OpenGL才會調用操作系統API,但是這仍然是原生渲染,因為OpenGL只是操作系統API的一個封裝庫,它并不像WebView渲染那樣需要JavaScript運行環境和CSS渲染器,所以不會有性能損失。
至此,我們已經介紹了Flutter UI系統和操作系統交互的這一部分原理,現在需要說一些它對應用開發者定義的開發標準。其實在前面的章節中,我們已經對這個標準非常熟悉了, 簡單概括就是:組合和響應式。我們要開發一個UI界面,需要通過組合其它Widget來實現,Flutter中,一切都是Widget,當UI要發生變化時,我們不去直接修改DOM,而是通過更新狀態,讓Flutter UI系統來根據新的狀態來重新構建UI。
講到這里,讀者可能發現Flutter UI系統和Flutter Framework的概念是差不多的,的確如此,之所以用“UI系統”,是因為其他平臺中可能不這么叫,我們只是為了概念統一,便于描述,讀者不必糾結于概念本身。
在接下來的小節中,我們先詳細介紹一下Element、RenderObject,它們是組成Flutter UI系統的基石。最后我們在分析一下Flutter應用啟動和運行的整體過程。
- 緣起
- 起步
- 移動開發技術簡介
- Flutter簡介
- 搭建Flutter開發環境
- 常見配置問題
- Dart語言簡介
- 第一個Flutter應用
- 計數器示例
- 路由管理
- 包管理
- 資源管理
- 調試Flutter APP
- Dart線程模型及異常捕獲
- 基礎Widgets
- Widget簡介
- 文本、字體樣式
- 按鈕
- 圖片和Icon
- 單選框和復選框
- 輸入框和表單
- 布局類Widgets
- 布局類Widgets簡介
- 線性布局Row、Column
- 彈性布局Flex
- 流式布局Wrap、Flow
- 層疊布局Stack、Positioned
- 容器類Widgets
- Padding
- 布局限制類容器ConstrainedBox、SizeBox
- 裝飾容器DecoratedBox
- 變換Transform
- Container容器
- Scaffold、TabBar、底部導航
- 可滾動Widgets
- 可滾動Widgets簡介
- SingleChildScrollView
- ListView
- GridView
- CustomScrollView
- 滾動監聽及控制ScrollController
- 功能型Widgets
- 導航返回攔截-WillPopScope
- 數據共享-InheritedWidget
- 主題-Theme
- 事件處理與通知
- 原始指針事件處理
- 手勢識別
- 全局事件總線
- 通知Notification
- 動畫
- Flutter動畫簡介
- 動畫結構
- 自定義路由過渡動畫
- Hero動畫
- 交錯動畫
- 自定義Widget
- 自定義Widget方法簡介
- 通過組合現有Widget實現
- 實例:TurnBox
- CustomPaint與Canvas
- 實例:圓形漸變進度條(自繪)
- 文件操作與網絡請求
- 文件操作
- Http請求-HttpClient
- Http請求-Dio package
- 實例:Http分塊下載
- WebSocket
- 使用Socket API
- Json轉Model
- 包與插件
- 開發package
- 插件開發:平臺通道簡介
- 插件開發:實現Android端API
- 插件開發:實現IOS端API
- 系統能力調用
- 國際化
- 讓App支持多語言
- 實現Localizations
- 使用Intl包
- Flutter核心原理
- Flutter UI系統
- Element和BuildContext
- RenderObject與RenderBox
- Flutter從啟動到顯示