Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android React Native使用原生UI組件

Android React Native使用原生UI組件

編輯:關於Android編程

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 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");
    }
}" data-snippet-id="ext.329b12fe654599976cf9c9288406e94b" data-snippet-saved="false" data-csrftoken="YovcNaBu-lenjyfTe3r17RMPlzP81oURyVgs" data-codota-status="done">public class ReactWebViewManager extends SimpleViewManager {
    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的注冊。

 createNativeModules(ReactApplicationContext reactContext) {

        return Collections.emptyList();;
    }

    @Override
    public List> createJSModules() {
        return Collections.emptyList();
    }

    @Override
    public List createViewManagers(ReactApplicationContext reactContext) {
        return Arrays.asList(
                new ReactWebViewManager());
    }
}
" data-snippet-id="ext.b8393c10894123c26f8f90dc93c90cac" data-snippet-saved="false" data-csrftoken="pAWMZxSf-LITk3G4glq3DgVmMEiqiHgeAN6k" data-codota-status="done">public class AppReactPackage implements ReactPackage {
    @Override
    public List createNativeModules(ReactApplicationContext reactContext) {

        return Collections.emptyList();;
    }

    @Override
    public List> createJSModules() {
        return Collections.emptyList();
    }

    @Override
    public List createViewManagers(ReactApplicationContext reactContext) {
        return Arrays.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 (
    
        
   
    );
  },   

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

這裡寫圖片描述

這還只是最基礎的將原始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層也需要進行一定程度的改造,最終的代碼如下

;
  }
}
WebView.propTypes = {
    url: PropTypes.string,
    html: PropTypes.string,
    onScrollChange: PropTypes.func,
};


var RCTWebView = requireNativeComponent('RCTWebView', WebView,{
    nativeOnly: {onChange: true}
});
module.exports = WebView" data-snippet-id="ext.d77348022d402d3fbda2fc1aea163b84" data-snippet-saved="false" data-csrftoken="M7VXVSiz-JsluEvZfqm_oyONV-uHimEkfOvM" data-codota-status="done">'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 ;
  }
}
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 (



);
},
onWebViewScroll:function(event){
    console.log(event);

},

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

這裡寫圖片描述

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

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved