從Android到ReactNative開發(三、自定義原生控制元件支援)

carguo發表於2018-08-22

 恍惚間3個月過去了,作為揭棺而起的失蹤人口,遲來的第三篇,也是react native原生相關的最後的一篇,是時候給收個尾了。這次就不廢話了,直接上主題( ̄^ ̄)ゞ。

 react native的高效,在於其中大部分元件,都是基於原生封裝的,js中對元件的配置與操作,最終都會轉化為native控制元件行為。以上的這段廢話,總結起來就是:react native通過統一的介面封裝,把原生控制元件轉為js元件使用。

 既然有官方封裝,那肯定少不了自定義控制元件。react native自定義元件還是很方便的,關鍵就在於ViewManager/ViewGroupManager。從類名上,很明顯是對應原生中的View和ViewGroup。

(PS :react native 中的View元件,封裝的其實是ViewGroupManager,所以View元件才可以包裹子元件,元件中的ZIndex屬性,其實就是子元件在add到ViewGroup中先後,如下圖)

 其他的內部細節就不深究咯,愉悅的奔向主題吧(˶‾᷄ ⁻̫ ‾᷅˵)。注意,下方程式碼分析大部分來自以下路徑:

//js元件
node_modules/react-native/Libraries/Components/View
node_modules/react-native/Libraries/Components/WebView

//原生java
react-native-0.xx.x/com.facebook/react/views/view
react-native-0.xx.x/com.facebook/react/views/webview

1、繼承ViewGroupManager

 首先我們需要實現一個XXXGroupManager,繼承於ViewGroupManager。其中最主要的便是過載實現getName和creatViewInstance兩個方法。

  • getName 指定了XXXGroupManager在js元件中獲取的名稱。
  • creatViewInstance 建立了自定義控制元件在Manager中使用,這裡只要將你在原生端的自定義控制元件,生成即可。

 js元件中,使用requireNativeComponent,可以通過上面中getName指定的名稱,獲取到對應的控制元件,如下圖,通過獲取到的控制元件,就可以配置對應的介面啦ε-(´∀`; )。

關於requireNativeComponent的使用說明參考下圖

2、設定自定義控制元件屬性

 react native 提供 @ReactProp@ReactPropGroup 註解,為js元件提供介面,配置原生控制元件的屬性。如下圖1,name = “borderStyle” 表示,js元件可以通過borderStyle設定控制元件的borderStyle,如圖2。如果需要預設值,可以增加default屬性。

圖1

圖2

 這裡需要注意,@ReactPropGroup是一組相近的屬性設定註解,如設定UI的上下左右的不同寬度,原生中通過index判斷,而它們在js端元件的設定,可以統一到原生中的一個介面。

圖3

3、原生控制元件操作JS元件

 react native提供原生控制元件對js元件的互動支援,和上一篇文章類似,也是通過事件機制傳送,傳送訊息到js元件中,js元件通過監聽事件的callback處理訊息。

 首先,在 UIManagerModuleConstants.java 中,如圖4,react native預設對映了一些元件的訊息事件名,如topChange在js元件中通過onChange監聽,這樣在原始中通過topChange傳送的訊息,就可以在元件中的onChange接收到訊息。

 訊息中的引數,可以通過WritableMap傳遞資料,利用rctEventEmitter傳送訊息。

圖4

圖5

 有時候,你可能還需要自定義自己的訊息名,那麼你需要重寫
getExportedCustomDirectEventTypeConstants ,只有註冊了你的對映訊息關係,才可以在js元件中,正常接收到你自定的訊息名的訊息。

圖6

圖7

4、js元件操作原生控制元件

 既然原生控制元件可以操作元件,那麼js元件也有控制原生控制元件的需求。這時候我們可以過載 getCommandsMap ,用來註冊js元件支援的操作行為,通過 receiveCommand 處理操作,如在js元件中呼叫reload,就會觸發原生XXXGroupManager中receiveCommand的root.reload,從而與原生控制元件互動。

圖9中,通過UIManager,傳送命令到原生。

圖8

圖9

 這類使用方式,類似的使用場景有,例如

//textInput元件中主動獲取焦點
UIManager.dispatchViewManagerCommand(
                    ReactNative.findNodeHandle(this.textInput),
                    UIManager.AndroidTextInput.Commands.focusTextInput,
                    null);

5、js端元件實現

 最終在原生端配置結束後,js端配置完對應邏輯,通過 module.exports = WebView 匯出元件使用。

結言

 拖了這麼久,react native和andorid原生相關的文章終於收尾啦(◐‿◑),也算是對react native的一個里程碑吧。在實際開發中,react native的程式碼的複用率還是挺高的,作為跨平臺開發的一種,還是蠻推薦大家嘗試下。

 接下來有時間會把github的demo完善下,畢竟demo落下的有點多了,歡迎大家關注喲ε-(´∀`; )。

個人github入口:https://github.com/CarGuo

還記得我嗎?


相關文章