React Native十五:原生UI组件

在如今的App中,已经有成千上万的原生UI组件了——其中的一些是平台的一部分,另一些可能来自于一些第三方库,而且可能你自己还收藏了很多。React Native已经封装了大部分最常见的组件,譬如ScrollView和TextInput,但不可能封装全部组件。而且,说不定你曾经为自己以前的App还封装过一些组件,React Native肯定没法包含它们。幸运的是,在React Naitve应用程序中封装和植入已有的组件非常简单。
本向导会引导你如何构建一个原生UI组件,带领你了解React Native核心库中WebView组件的具体实现。
一、WebView样例
在这个例子里,我们来看看为了让JavaScript中可以使用WevView,我们以react-native init AwesomeProject创建示例项目进行演示,项目完成目录如下:

提供原生视图很简单,主要有如下几个步骤:
     1.创建一个ViewManager的子类,实现createViewInstance方法,使用@ReactProp(或@ReactPropGroup)注解;
     2.创建一个把ReactPackage的子类,把这个视图管理类注册到应用程序包的createViewManagers里;
     3.在MainActivity中的getPackages方法中添加ReactPackage的子类;
     4.实现JavaScript模块WebView.js,index.android.js;
ReactWebViewManager.java类:
public class ReactWebViewManager extends SimpleViewManager{
    public static final String REACT_CLASS = "MyWebView";

    @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");
    }
}
2.创建一个把ReactPackage的子类,把这个视图管理类注册到应用程序包的createViewManagers里;
AppReactPackage.java类
public class AppReactPackage implements ReactPackage{
    ...... ......
    @Override
    public List createViewManagers(ReactApplicationContext reactContext) {
        return Arrays.asList(
                new ReactWebViewManager(),new ReactRTCWebViewManager());
    }
}
3.在MainActivity中的getPackages方法中添加ReactPackage的子类;
MainActivity.java类
public class MainActivity extends ReactActivity {
    ...... ...... 
    @Override
    protected List getPackages() {
        return Arrays.asList(
            new MainReactPackage(),new AppReactPackage()
        );
    }
}
4.实现JavaScript模块WebView.js,index.android.js;
WebView.js文件
var { requireNativeComponent,PropTypes  } = require('react-native');

var iface = {
  name: 'WebView',
  propTypes: {
    url: PropTypes.string,
    html: PropTypes.string,
  },
};

module.exports = requireNativeComponent('MyWebView', iface);
index.android.js文件
import React from 'react';
import {
  AppRegistry,
  StyleSheet,
  Text,
  View
} from 'react-native';

var WebView=require('./WebView');

class MyAwesomeApp extends React.Component {
  render() {
    return (
      
        Hello, World
        
      
    )
  }
}
var styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
  },
  hello: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
  },
});

AppRegistry.registerComponent('AwesomeProject', () => MyAwesomeApp);
5.运行效果如下:

提示1:如果在运行的过程中,报错如下

处理1:修改该部分代码如下,module.exports = requireNativeComponent('MyWebView', iface,{nativeOnly:{
                                                             'scaleX': true,
                                                             'scaleY': true,
                                                             'testID': true,
                                                             'decomposedMatrix': true,
                                                             'backgroundColor': true,
                                                             'accessibilityComponentType': true,
                                                             'renderToHardwareTextureAndroid': true,
                                                             'translateY': true,
                                                             'translateX': true,
                                                             'accessibilityLabel': true,
                                                             'accessibilityLiveRegion': true,
                                                             'importantForAccessibility': true,
                                                             'rotation': true,
                                                             'opacity': true,
                                                             'onLayout': true,
                                                           }});
二、事件
现在我们已经知道了怎么导出一个原生视图组件,并且我们可以在JS里很方便的控制它了。不过我们怎么才能处理来自用户的事件,譬如缩放操作或者拖动?当一个原生事件发生的时候,它应该也能触发JavaScript端视图上的事件,这两个视图会依据getId()而关联在一起。
下面我们就以基于原始WebView组件,在JavaScript层处理它的滚动事件,实现如下:
1. 创建RTCWebView继承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);
    }
}
2.创建ReactRTCWebViewManager,在createViewInstance方法,在里面返回我们实现的子类RTCWebView
public class ReactRTCWebViewManager extends SimpleViewManager{
    public static final String REACT_CLASS = "MyRTCWebView";
    ...... ...... 

    @Override
    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;
    }
    ...... ...... 
}
3. 仍然再AppAppReactPackage注册实现ReactRTCWebViewManager(该部分省略);
4.JavaScript层创建RTCWebView.js文件,改造index.android.js文件:
RTCWebView.js文件
'use strict';

var React = require('react');
var ReactNative = require('react-native');
var {
  requireNativeComponent,
  PropTypes
} = ReactNative;


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: React.PropTypes.string,
    html: React.PropTypes.string,
    onScrollChange: React.PropTypes.func,
};

var RTCWebView = requireNativeComponent('MyRTCWebView', WebView,{nativeOnly:{
                                                                    'scaleX': true,
                                                                    'scaleY': true,
                                                                    'testID': true,
                                                                    'decomposedMatrix': true,
                                                                    'backgroundColor': true,
                                                                    'accessibilityComponentType': true,
                                                                    'renderToHardwareTextureAndroid': true,
                                                                    'translateY': true,
                                                                    'translateX': true,
                                                                    'accessibilityLabel': true,
                                                                    'accessibilityLiveRegion': true,
                                                                    'importantForAccessibility': true,
                                                                    'rotation': true,
                                                                    'opacity': true,
                                                                    'onLayout': true,
                                                                    'source': true,
                                                                    'javaScriptEnabled': true,
                                                                    'domStorageEnabled': true,
                                                                    'injectedJavaScript': true,
                                                                    'userAgent': true,
                                                                    'onChange': true,
                                                                    }});
module.exports = WebView
index.android.js文件
'use strict';

import React from 'react';
import {
  AppRegistry,
  StyleSheet,
  Text,
  View
} from 'react-native';

var WebView=require('./RTCWebView');

class MyAwesomeApp extends React.Component {
  render() {
    return (
      
        Hello, World
        
      
    )
  }

  onWebViewScroll(event) {
      console.log(event);
  }
}
var styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
  },
  hello: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
  },
});

AppRegistry.registerComponent('AwesomeProject', () => MyAwesomeApp);
5.Debug Js,运行后滑动Webview,在Chrome的Develop Tools中显示如下:

提示2:如果在Debug JS的过程中,出现如下报错,导致无法正常Debug
The method /launch-chrome-devtools is deprecated. You are  probably using an application created with an older CLI with the  packager of a newer CLI. Please upgrade your application: https://facebook.github.io/react-native/docs/upgrading.html
处理2:尝试安装新版的Chrome浏览器版本,和react-native的版本。该demo使用的react-native版本为0.27.1-rc2,具体如何升级请查看《版本升级》章节。

你可能感兴趣的:(React,Native)