Weex-iOS原始碼-CSS Layout 分析

王小樹發表於2019-02-19

前言

這篇文章主要是對Weex iOS端原始碼中的佈局原理進行分析,並根據原理寫了一個Demo,歡迎大家進行交流溝通。

Layout 介紹

Layout是FaceBook開源的一個跨端CSS佈局引擎。
Weex 引入了Layout 在原來的基礎上進行名稱空間上的調整,
Layout在Weex中主要是作為一個CSS引數的容器,對CSS的引數的管理。

Layout原始碼

Layout原始碼由C語言編寫,主要包含可以儲存CSS引數的結構體、列舉,以及一些相關的C函式。
1、結構體、列舉
Layout.h檔案中宣告瞭對應於CSS屬性的一些結構體和列舉體
如:

css_style_t
css_layout_t
css_node_t
css_direction_t
css_flex_direction_t
css_justify_t
css_align_t
css_position_type_t
css_wrap_type_t
css_position_t
···
複製程式碼

對CSS有了解的夥伴可以看出,這些結構體的命名上和CSS的屬性是相對應的
其中比較核心的一個資料結構體是css_node_t,裡面包含了CSS佈局需要的大部分引數:

Weex-iOS原始碼-CSS Layout 分析

2、C函式
layout中實現了一些管理css_node_t等結構體的生命週期的C函式:

css_node_t *new_css_node(void);
void init_css_node(css_node_t *node);
void free_css_node(css_node_t *node);
void layoutNode(css_node_t *node, float maxWidth, float maxHeight, css_direction_t parentDirection);
void resetNodeLayout(css_node_t *node);
複製程式碼

這些函式包括了初始化、析構、重置等功能。

Weex佈局原理

大概流程:

Weex-iOS原始碼-CSS Layout 分析
一、通過JS載入資料

Weex通過JSContext讓APP與JS進行互動,相關載入的資料通過JSValue進行載入。
JSValue資料結構大致如下:

    {
        attr = {
            data-v-e9c9dede = ;
        };
        style = {
            bottom = 48wx;
            position = absolute;
            width = 0;
            left = 0;
            top = 0;
            opacity = 0;
            backgroundColor = rgba(0,0,0,0.5);
        };
        type = div;
        event = (
                 click
                 );
        ref = 558;
    }
複製程式碼

通過JS獲取JSValue:

Weex-iOS原始碼-CSS Layout 分析
二、轉換成iOS原生可用的佈局資料 存進css_node_t

在獲取JSValue之後通過toDictionary方法轉化成原生直接可用的NSDictionary格式的資料。
再將NSDictionary資料轉換到css_node_t中
Weex中封裝了一些巨集用於轉換,如:

WX_STYLE_FILL_CSS_NODE
WX_STYLE_FILL_CSS_NODE_PIXEL
WX_STYLE_FILL_CSS_NODE_ALL_DIRECTION
複製程式碼

這些巨集主要是獲取NSDictionary中各個key的value(即CSS屬性的資料)計算成原生布局可用的資料,存入css_node_t 中對應的成員裡。
Weex提供了一些方法將CSS屬性的資料計算轉換成佈局可用的資料:
例如數值轉換:

Weex-iOS原始碼-CSS Layout 分析

Weex中,CSS的width,height等屬性單位有wx和px.+ (CGFloat)CGFloat:(id)value方法就是將其轉換成原生布局可以用的數值。

三、進行佈局

需要佈局時,從css_node_t取出資料,對View進行佈局。
如:

Weex-iOS原始碼-CSS Layout 分析

css_node_t中取出資料,計算出frame(即View的位置和大小),進行佈局

其他細節

佈局數值的精確度

在layout中實現了一個比較函式eq:

static bool eq(float a, float b) {
  if (isUndefined(a)) {
    return isUndefined(b);
  }
  return fabs(a - b) < 0.0001;
}
複製程式碼

從中可以看出,所以在weex中佈局相關數值的精確度偏差最低為0.0001,如0.00011和0.00019在weex佈局中視為一樣。

標籤採用繪製成圖片的形式展示

從原始碼可以看出,(對應weex原始碼中的WXTextComponent)用了繪製成圖片的形式展示:

Weex-iOS原始碼-CSS Layout 分析

這也是導致weex頁面記憶體開銷比原生大很多的主要原因之一。
我個人認為用圖片來展示的原因是:
通過CSS佈局面對不同尺寸螢幕時以及各種佈局方案下,各個元件會有各種各樣的拉伸場景,UILabe中文字的大小font需要隨著拉伸進行變化,通過計算來讓font適應各種拉伸場景需要考慮的場景太多太複雜。
因此weex採用了圖片進行展示的方法解決這個問題。

相關文章