2、Widget、Element、RenderObjectcss
5、layout 流程分析react
7、Paint 繪製(2)canvas
9、Flutter 小實踐bash
在界面上顯示一個寬爲 300、高爲 200 矩形, 以下圖所示服務器
前端實現方式不少 (1)domweex
<html>
<style type='text/css'>
.demo {
width: 300px;
height: 200px;
background: #f00;
}
</style>
<body>
<div class='demo'></div>
</body>
</html>
複製代碼
html文本描述了頁面應該有哪些功能,css告訴瀏覽器該長什麼樣 瀏覽器引擎經過解析html和css,翻譯成一些列的預約義UI控件 而後UI控件去調用操做系統繪圖指令去繪製圖像展示給用戶
(2) canvas
<html>
<body>
<script>
var c= document.createElement("canvas");
var ctx=c.getContext("2d");
ctx.fillStyle="#FF0000";
ctx.fillRect(0,0,300,200);
document.body.append(c);
</script>
</body>
</html>
複製代碼
能夠經過畫布繪製,如以上代碼所示, 經過建立 canvas 節點,獲取 canvas 繪製上下文,調用相關 API, 即可繪製一個矩形,並 append 到 body 節點中。
顯示器(屏幕)是由一個個物理顯示單元(像素點)組成,而每個像素點能夠發出多種顏色,顯示器成相的原理就是在不一樣的物理像素點上顯示不一樣的顏色,最終構成完整的圖像。圖形計算和繪製都是由相應的硬件來完成,操做系統通常屏蔽了這些底層硬件操做指令,提供一些封裝後的API供操做系統之上的應用調用,可是對於應用開發者來講,直接調用這些操做系統提供的API是比較複雜和低效的,所以幾乎全部用於開發GUI程序的編程語言都會在操做系統之上再封裝一層,將操做系統原生API封裝在一個編程框架和模型中,而後定義一種簡單的開發規則來開發GUI應用程序,而這一層抽象,就是所謂的「UI」系統,如Android SDK正是封裝了Android操做系統API,提供了一個「UI描述文件XML+Java操做DOM」的UI系統,而iOS的UIKit 對View的抽象也是同樣的,他們都將操做系統API抽象成一個基礎對象(如用於2D圖形繪製的Canvas),而後再定義一套規則來描述UI,如UI樹結構,UI操做的單線程原則等。
Weex
上圖是weex 工做流程圖,WEEX框架中核心的部分是JavaScript Runtime。當JSBundle從服務器端下載完成以後,WEEX在Android、iOS和Web端會運行一個JavaScript引擎來執行JSBundle,同時向各終端的渲染層發送渲染指令,並調度客戶端的渲染引擎實現視圖渲染、事件綁定和處理用戶交互等操做。
ReactNative
上圖爲 reactnative 流程架構圖,和 weex 相似, reactNative 全部的標籤也不是真實控件,JS 代碼中所生成存的 dom,最後都是由 Native 端解析,再獲得對應的Native控件渲染。
不論是 Weex 仍是 ReactJS,自身是不直接繪製UI的,而是調用原生組件執行頁面渲染操做。Bridges則是用來繪製指令給原生組件進行繪製
Flutter
與 React Native 和 WEEX 使用原生組件渲染界面不一樣,Flutter並不須要使用原生組件來渲染界面,而是使用自帶的渲染引擎(Engine層)來繪製頁面組件。
以下圖所示,Flutter框架主要由 Framework 層和 Engine 層組成,其中 Engine 層 其以Skia做爲其2D渲染引擎,有本身的UI繪製機制。
在 Flutter 中,也有 Canvas 的概念,Engine 層向 Dart 層的暴露了 Canvas, PictureRecorder 等接口,利用它們能夠繪製任何本身想顯示的東西~如如下代碼,相似 js 中調用 canvas 相似
void main() {
// 獲取繪製圖層
OffsetLayer rootLayer = new OffsetLayer();
PictureLayer pictureLayer = PictureLayer(Rect.zero);
rootLayer.append(pictureLayer);
// 繪製圖形
pictureLayer.picture =
createSolidRectanglePicture(Color(0xFFFF0000), 300, 200);
rootLayer.updateSubtreeNeedsAddToScene();
SceneBuilder sceneBuilder = SceneBuilder();
rootLayer.addToScene(sceneBuilder);
Scene scene = sceneBuilder.build();
window.onDrawFrame = () {
// 將繪製的圖層輸送到GPU
window.render(scene);
};
window.scheduleFrame();
}
複製代碼
簡單地講,flutter 提供一張畫布、咱們能夠在畫布上天馬星空,繪製任何本身想繪製的東西
Vsync 相關概念
在計算機系統中,CPU、GPU和顯示器以一種特定的方式協做:CPU將計算好的顯示內容提交給 GPU,GPU渲染後放入幀緩衝區,它們是圖像生產者,往幀緩衝區(BufferQueue) 不斷填充數據, 顯示器能夠理解爲消費者,從幀緩衝區取幀數據(BufferQueue)中獲取數據, 負責把渲染後的內容呈現到屏幕上。
爲了更新顯示畫面,顯示器是以固定的頻率刷新(從GPU取數據),好比有一部手機屏幕的刷新頻率是 60Hz。當一幀圖像繪製完畢後準備繪製下一幀時,顯示器會發出一個垂直同步信號(如VSync), 60Hz的屏幕就會一秒內發出 60次這樣的信號, 這個信號是用來同步 CPU、GPU 和顯示器的工做的,即提示 CPU 和 GPU 進行下一幀工做的信號, Android系統每隔16.6ms發出VSYNC信號,來通知界面進行輸入、動畫、繪製等動做
爲何須要 Vsync
Refresh Rate:表明了屏幕在一秒內刷新屏幕的次數,這取決於硬件的固定參數,例如60Hz Frame Rate:表明了GPU在一秒內繪製操做的幀數,例如30fps,60fps
若是沒有 Vsync 機制,容易產生如下兩種狀況
(1)供過於求 如今的顯卡一般能夠將CS的幀率渲染到120以上,即120FPS。可一般咱們使用的顯示器只能達到60HZ的刷新率。顯然,即便顯卡在1秒內將畫面變化了120次,但顯示器只有展現其中60幅的能力。這種時候,咱們感知的流暢度實際上是60FPS,顯卡在顯示器兩次刷新的一個週期內,輸出了兩幀畫面,前一幀就會被看成無效幀丟棄、多餘的幀是無效幀,對畫面效果提高沒有任何做用。
(2)供不該求
若是圖像生成的速率低於圖像消費速率,即供不該求的狀況下,容易產生卡頓的現象,如上圖中:
第一個 16ms:Display顯示第0幀,CPU處理完第一幀後,GPU緊接其後處理繼續第一幀
第二個16ms:由於早在上一個16ms時間內,第1幀已經由CPU,GPU處理完畢。故Display能夠直接顯示第1幀。顯示沒有問題。但在本16ms期間,CPU和GPU卻並未及時去繪製第2幀數據,而是在本週期快結束時,CPU/GPU纔去處理第2幀數據
第三個16ms: 此時Display應該顯示第2幀數據,但因爲CPU和GPU尚未處理完第2幀數據,故Display只能繼續顯示第一幀的數據,結果使得第1幀多畫了一次
Vsync 機制是起到一個協調做用,顯卡在渲染每一幀以前會等待垂直同步信號,只有顯示器完成了一次刷新時,發出垂直同步信號,顯卡纔會渲染下一幀,確保刷新率和幀率保持同步,以達到供需平衡的效果,防止卡頓現象
Flutter Vsync 流程