編輯:關於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加載處理,你再上下滑動,就會看到控制台的輸出,如下
組件的全部流程,可以看出React Native官方已經為我們做了很好的封裝,我們只需要編寫少量的代碼,就可以使用原生UI組件了。
Android TextView兩端對齊 Android中的TextView控件默認是做不到兩端對齊的,都是左對齊。可能的原因是安卓默認數字、字母不能為第一行以後每行
Android 繪圖機制:canvas初解 Canvas 即“畫布”的意思,在Android中用其來進行2D繪畫。 在使用can
網上商城4--首頁二級分類的查詢,4--二級分類 1.創建表 CREATE TABLE `categorysecond` ( `csid` int(1
Android基礎入門教程——8.4.3 Android動畫合集之屬性動畫-初見 Android基礎入門教程——8.4.3 Android動畫
[FastDev4Android框架開發]神器ViewGragHelpe