使用BindingX開發客戶端炫酷動畫

xiangzhihong發表於2018-09-16

Weex 是一套簡單易用的跨平臺開發方案,能以 web 的開發體驗構建高效能、可擴充套件的 native 應用,為了做到這些,Weex 與 Vue 合作,使用 Vue 作為上層框架,並遵循 W3C 標準實現了統一的 JSEngine 和 DOM API,這樣一來,你甚至可以使用其他框架驅動 Weex,打造三端一致的 native 應用。

簡介

基本概念

為了方便使用 BindingX ,開發者需要理解以下幾個概念:表示式 、 事件型別 、 屬性變換。

表示式

表示式,是由數字、運算子、變數等以能求得數值的有意義排列方法所得的組合。譬如, x*3+10 就是一個表示式,當x被賦值時,整個表示式就會有一個明確的結果。通過表示式,我們就可以描述一個具體的互動行為,比如我們希望x從0變化到100時,透明度能從1變化到0.5,那麼表示式可以描述為: f(alpha) = 1-(x/100)*0.5。 在 BindingX 中,我們實現了一個輕量的表示式解析引擎用於執行表示式,除了基本的四則運算外,還支援三元運算子、數學函式等高階語法,能夠滿足絕大部分的場景。要檢視 BindingX 中支援的表示式語法,請參考《支援的表示式語法》

事件型別

現在你已經知道了 BindingX 是通過表示式來描述互動行為的,那麼表示式中的變數究竟是什麼呢? 答案是"不同的事件型別擁有不同的表示式變數"!那什麼是事件型別呢?在 BindingX 中,事件是指能夠驅動表示式數值變化的資料產生者,比如"使用者的手勢"、"列表的滾動" 甚至是"陀螺儀感知到的方向變化",每一種這樣的事件都對應著唯一的事件型別,比如"手勢"對應的事件型別就是 pan ,要檢視 BindingX 支援的所有事件型別,請參考文件: 《支援的事件型別》。 同時,每一種事件型別都對應著不同的表示式變數。比如,當事件型別為 pan 時,表示式變數就是x和y,分別代表手勢過程中橫向和縱向的偏移量。

屬性變換

表示式的執行結果最終會驅動UI變化,比如透明度、位移、背景色等, 屬性變換 就是用來描述這些屬性的。在 BindingX 中,支援常用的transform屬性變換,如translation、scale ,另外還包括透明度、寬高等屬性。要檢視所有支援的屬性變換,請參考文件:《支援的屬性》

背景與原理

在Weex環境下實現一些複雜的手勢互動效果可能會產生卡頓,這是因為每次手勢互動都會產生兩次js-native通訊。第一次是native call js,將手勢事件傳遞到js層交給前端處理,當js層接收到回撥後,會產生第二次通訊,js call native,用來驅動介面變化。與此同時,手勢回撥事件觸發的頻率是非常高的,頻繁通訊帶來的時間成本很可能導致介面無法在16ms中完成繪製,因而產生卡頓。下面是傳統方案的示意圖:

這裡寫圖片描述
基於此,Weex的基礎團隊提出了Expression Binding的方式來進行通訊。具體來說,就是在手勢開始的時候,將具體的手勢控制函式以表示式的形式傳遞給Native層,當手勢發生時,Native根據預置的表示式解析器去解釋執行表示式,並根據結果驅動檢視變化。這樣帶來的好處是大大的減少了native-js的通訊次數,下面是一個原理模型圖。
這裡寫圖片描述
事實上,Expression Binding 不僅僅可以解決手勢互動問題,任何js-native頻繁通訊+UI更新的場景理論上都可以複用這套方案。比如:

  • 監聽容器的滾動,並基於滾動距離等變數更新UI如最常見的視差動畫等;
  • 監聽陀螺儀方向變化資料,並更新UI;
  • 監聽時間變化,更新UI;

這裡寫圖片描述
因此,我們將原方案進行了橫向的擴充套件,實現了這些新的特性,並將它命名為BindingX。2018年三月,BindingX正式開源,並同時支援了React Native。

功能一覽

使用BindingX可以實現諸多負責的功能,主要有複雜動畫、陀螺儀、吸頂燈效果。

手勢監聽

BindingX能夠監聽元素的pan事件,基於此可以實現拖拽、卡片橫滑等跟手的互動效果。更令人驚喜的是,類似weex Slider這樣的元件現在也可以使用BindingX來實現。

這裡寫圖片描述
這裡寫圖片描述

動畫

在weex上實現動畫通常的做法是使用animation module,現在有了新的選擇。使用BindingX可以實現所有animation module能實現的效果,另外,BindingX內建了30多組常見的插值器,可以自由選擇,當然也可以使用cubicBezier貝塞爾曲線定製插值器,並且這些效果還支援在RN中使用。

這裡寫圖片描述

##陀螺儀 BindingX內建了陀螺儀監聽器,可以監聽裝置方向變化。這在很多富互動場景中非常實用,比如在手機淘寶裡,你可以看到很多基於陀螺儀的視差效果。

使用BindingX開發客戶端炫酷動畫

使用BindingX開發客戶端炫酷動畫

列表滾動監聽

BindingX能夠監聽列表等滾動容器的onScroll事件,通過它可以實現酷炫的視差動畫。

這裡寫圖片描述
這裡寫圖片描述

使用簡介

BiningX同時支援ReactNative和Weex,對於Weex來說不管你是使用Rax還是Vue DSL,都沒有關係。下面以Weex舉例來說明如何使用BindingX。

接入BindingX

第一步: 安裝依賴

安裝npm依賴。

npm install weex-bindingx --save
複製程式碼

然後在JS程式碼中引入BindingX模組。

import BindingX from weex-bindingx;
複製程式碼

第二步: 編寫表示式

根據業務場景,選擇您需要的EventType。 比如,要監聽手勢,evenType值為pan,監聽滾動容器scrollOffset變化,eventType值為scroll。

根據互動行為,選擇要改變的屬性,並編寫相應的表示式。比如,互動行為是"使用者橫滑100單位,透明度從1變化到0"。則屬性為"opacity",表示式為"1-x/100"。

第三步: 繫結表示式

根據第二步得到的eventType、Expression以及Property,呼叫 BindingX 模組的 bind 方法,完成繫結。例如:

let result = BindingX.bind({
    eventType: 'pan',      ==> 事件型別
    anchor: 'foo',          ==> anchor指的是事件的觸發者,如果是eventType是"orientation""timing",則不用填
    props: [
        {
            element: view.ref,    ==> 要改變的檢視的引用或者id
            expression: "1-x/100", ==> 表示式
            property: "opacity"    ==> 要改變的屬性
        }
    ]
})

複製程式碼

當呼叫bind方法之後,Native會啟動監聽,當目標事件(比如手指滑動、裝置方向變化等)發生的時候,便會執行您先前繫結的一組或者多組表示式。 bind 方法會返回一個JS物件,其中包含了一個 token 屬性,可以使用這個token取消繫結。

第四步: 取消繫結

在合適的時機呼叫 BindingX 的unbind方法取消繫結。比如,頁面不可見或者即將銷燬的時候。

BindingX.unbind({
    token: result.token,
    eventType: 'pan'
})
複製程式碼

實現細節

下面以Android為例從Native的視角介紹下BindingX的具體實現,首先我們來梳理整個流程:

1,前端通過宣告的方式定義具體的檢視變化,每個檢視變化過程都用一個三元組描述:

  • element: 目標元素。
  • property: 要改變的屬性。
  • expression: 表示式。通過工具生成抽象語法樹。

2,Native根據EventType註冊對應的事件監聽器,並將對映關係儲存起來; 3,當指定的事件發生的時候,Native自行消費先前繫結的所有表示式,計算結果,並根據結果對檢視進行更新。

整個過程可以用下面這張圖描述:

這裡寫圖片描述
在這個模型裡,輸入可以是手勢事件、滾動事件、陀螺儀方向變化事件,而輸出則是經過檢視變換的view,檢視變換的過程在Native完成。而檢視變換的規則是通過表示式來描述的,一個表示式在前端宣告之後,會先通過parser轉成Abstract syntax tree,Native會通過預置的解析器來解析表示式樹,並計算出結果,根據結果去驅動檢視進行改變。

其他

事實上,BindingX比我們想象的更加強大,在上面那張架構圖中,輸出部分畫的是transformed view,但是事實上除了view,BindingX還可以完成更多有趣的事情。比如:

  • BindingX和Lottie結合。用bindingX驅動lottie實現動畫;
  • BindingX和Weex SVG結合,實現好玩的軌跡動畫、路徑跟隨動畫,甚至是morph變形動畫;
  • BindingX和Shader結合,用BindingX來控制著色器!
  • ......

目前,為了更了更好的體現開源精神,並且讓更多的開發者使用Weex,Weex 的SDK正在做相關的升級,目的是在效能渲染和接入方面更加人性化。

相關文章