Android React Native使用原生UI組件

來源:互聯網
上載者:User

標籤:

Android React Native 已經將幾個常用的原生組件進行了封裝,比如 ScrollView 和 TextInput,但是並不是所有系統的原始組件都被封裝了,因此有的時候我們不得不自己動手封裝一下,從而能夠使用那些React Native沒有為我們封裝的原生組件,比如WebView,官方並沒有提供Android端的實現,那麼我們現在就動手封裝一下WebView。

之前寫過一篇文章Android React Native使用原生模組,而使用原生UI組件的方法和使用原生模組的方法十分類似。

首先,我需要繼承SimpleViewManager這個泛型類,和原生模組類似,需要重寫getName()方法,將UI組件名稱暴露給javascript層,接著需要重寫createViewInstance方法,在裡面返回我們需要使用的原生UI組件的執行個體,這裡就是WebView。然後就是暴露一些必要屬性給javascript層,為了簡單起見,我們這裡只暴露兩個屬性,一個是url,一個是html,一旦javascript層設定了url,就會載入一個網頁,而一旦設定了html,則會去載入這段html,而屬性的暴露是使用註解,將註解設定在對應的set方法上,之後再set方法中處理UI的更新,比如一旦設定了url,在setUrl裡面就要載入網頁。最終我們的ViewManager就是這樣子的

public class ReactWebViewManager extends SimpleViewManager<WebView> {    public static final String REACT_CLASS = "RCTWebView";    @Override    public String getName() {        return REACT_CLASS;    }    @Override    protected WebView createViewInstance(ThemedReactContext reactContext) {        WebView webView= new WebView(reactContext);        webView.setWebViewClient(new WebViewClient(){            @Override            public boolean shouldOverrideUrlLoading(WebView view, String url) {              view.loadUrl(url);                return true;            }        });        return webView;    }    @ReactProp(name = "url")    public void setUrl(WebView view,@Nullable String url) {        Log.e("TAG", "setUrl");        view.loadUrl(url);    }    @ReactProp(name = "html")     public void setHtml(WebView view,@Nullable String html) {        Log.e("TAG", "setHtml");        view.loadData(html, "text/html; charset=utf-8", "UTF-8");    }}

和原生模組一樣,原生UI組件也需要進行註冊,實現ReactPackage介面,進行WebView的註冊。

public class AppReactPackage implements ReactPackage {    @Override    public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {        return Collections.emptyList();;    }    @Override    public List<Class<? extends JavaScriptModule>> createJSModules() {        return Collections.emptyList();    }    @Override    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {        return Arrays.<ViewManager>asList(                new ReactWebViewManager());    }}

將這個ReactPackage添加到ReactInstanceManager執行個體中去

  .addPackage(new AppReactPackage())

然後在javascript層建立一個WebView.js檔案。輸入下面的內容

‘use strict‘;var { requireNativeComponent,PropTypes  } = require(‘react-native‘);var iface = {  name: ‘WebView‘,  propTypes: {    url: PropTypes.string,    html: PropTypes.string,  },};module.exports = requireNativeComponent(‘RCTWebView‘, iface);

可以看到,我們只是在裡面指定了屬性的類型。

到目前為止,你已經可以使用這個WebView組件了。

var WebView=require(‘./WebView‘);render: function() {    return (    <View style={styles.container}>        <WebView  url="https://www.baidu.com" style={{width:200,height:400}}></WebView>   </View>    );  },   

這裡只是簡單載入了一下百度首頁,有一點需要特別注意,就是組件的寬度高度一定要設定,否則你會看不到這個組件。最終效果如下。

這還只是最基礎的將原始UI組件顯示出來,而更為常見的卻是事件,比如我們需要在javascript層處理這個WebView的滾動事件,這時候又要怎麼做呢。

這時候我們就需要繼承WebView,重寫對應的事件,然後將事件傳遞給javascript層了

public class RTCWebView extends WebView{    public RTCWebView(Context context) {        super(context);    }    public RTCWebView(Context context, AttributeSet attrs) {        super(context, attrs);    }    public RTCWebView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);    }    @Override    protected void onScrollChanged(int l, int t, int oldl, int oldt) {        super.onScrollChanged(l, t, oldl, oldt);        Log.e("TAG","onScrollChanged");        WritableMap event = Arguments.createMap();        event.putInt("ScrollX", l);        event.putInt("ScrollY", t);        ReactContext reactContext = (ReactContext)getContext();        reactContext.getJSModule(RCTEventEmitter.class).receiveEvent(                getId(), "topChange", event);    }}

我們重寫了滾動時回調的onScrollChanged方法,構造了一個WritableMap 對象,將ScrollX和ScrollY傳入,然後調用reactContext.getJSModule(RCTEventEmitter.class).receiveEvent(getId(), “topChange”, event);將事件發生到javascript層,注意topChange對應著javascript層的onChange方法,這個映射關係在UIManagerModuleConstants類中。

然後我們需要修改ReactWebViewManager 中的createViewInstance方法,在裡面返回我們實現的子類,就像這樣子

protected WebView createViewInstance(ThemedReactContext reactContext) {        WebView webView= new RTCWebView(reactContext);        webView.setWebViewClient(new WebViewClient(){            @Override            public boolean shouldOverrideUrlLoading(WebView view, String url) {              view.loadUrl(url);                return true;            }        });        return webView;    }

而javascript層也需要進行一定程度的改造,最終的代碼如下

‘use strict‘;var React = require(‘react-native‘);var {  requireNativeComponent,  PropTypes} = React;class WebView extends React.Component {  constructor() {    super();    this._onChange = this._onChange.bind(this);  }  _onChange(event: Event) {    if (!this.props.onScrollChange) {      return;    }    this.props.onScrollChange({ScrollX:event.nativeEvent.ScrollX,ScrollY:event.nativeEvent.ScrollY});  }  render() {    return <RCTWebView {...this.props} onChange={this._onChange} />;  }}WebView.propTypes = {    url: PropTypes.string,    html: PropTypes.string,    onScrollChange: PropTypes.func,};var RCTWebView = requireNativeComponent(‘RCTWebView‘, WebView,{    nativeOnly: {onChange: true}});module.exports = WebView

不要問我為什麼是這樣子的,因為官方文檔上就是在這麼寫的,你只需要複製代碼,進行修改即可,詳見文檔Native UI Components

這裡需要注意的就是function.bind(this)的文法了,有興趣的自己去網上搜,這塊我也講不清楚,畢竟沒怎麼學過javascript和React,怕誤人子弟。在onChange函數中,我們進行判斷,如果屬性onScrollChange沒有設定,就直接return,否則就調用設定的onScrollChange屬性值(該值是一個函數類型),將Java層傳入的兩個參數傳到該函數中去,{ScrollX:event.nativeEvent.ScrollX,ScrollY:event.nativeEvent.ScrollY}

然後我們來進行調用

var WebView=require(‘./WebView‘);render: function() {return (<View style={styles.container}><WebView onScrollChange={this.onWebViewScroll} url="https://www.baidu.com" style={{width:200,height:400}}></WebView></View>);},onWebViewScroll:function(event){    console.log(event);},

這時候等待WebView載入處理,你再上下滑動,就會看到控制台的輸出,如下

以上就是使用原生UI組件的全部流程,可以看出React Native官方已經為我們做了很好的封裝,我們只需要編寫少量的代碼,就可以使用原生UI組件了。

Android React Native使用原生UI組件

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.