編輯:關於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組件了。
安卓手機QQ自帶截圖功能,iPad、iPhone則需要使用iOS系統自帶的截圖方法或者第三方APP。下面就隨小編分別來看看,安卓手機QQ和iOS系統的ipa
昨天琢磨了下Android的輸入法彈出模式,突然發現利用動態切換輸入法的彈出模式可以解決輸入法抖動的問題。具體是怎樣的抖動呢?我們先看微博的反面教材。 【具體表現為:表情
本文實例為大家分享了Android內存中存儲用戶名和密碼的方法,供大家參考,具體內容如下首先是配置文件:<LinearLayout xmlns:android=ht
之前介紹了Android系統下三種數據存儲形式,http://www.jb51.net/article/99468.htm。今天補充介紹另外兩種,分別是內容提供者和網絡存