Android React Native使用原生UI组件

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<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的注册。

 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<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层也需要进行一定程度的改造,最终的代码如下

;
  }
}
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 <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组件了。

时间: 2024-11-03 03:42:21

Android React Native使用原生UI组件的相关文章

推荐 11 款 React Native 开源移动 UI 组件

推荐 11 款 React Native 开源移动 UI 组件 oschina 发布于 10个月前,共有 14 条评论 本文推荐 11 个非常棒的 React Native 开源组件,希望能给移动应用开发者提供帮助. React Native 是近期 Facebook 基于 MIT 协议开源的原生移动应用开发框架,已经用于 Facebook 的生产环境.React Native 可以使用最近非常流行的 React.js 库来开发 iOS 和 Android 原生 APP. 1. iOS 表单处理

Android React Native使用原生模块

有时候我们的App需要访问平台API,并且React Native可能还没有相应的模块包装:或者你需要复用一些Java代码,而不是用Javascript重新实现一遍:又或者你需要实现某些高性能的.多线程的代码,譬如图片处理.数据库.或者各种高级扩展等等. 而用React Native可以在它的基础上编写真正原生的代码,并且可以访问平台所有的能力.如果React Native还不支持某个你需要的原生特性,你应当可以自己实现该特性的封装. 不过在开始编写代码使用原生模块前,有一个知识点需要掌握,免得

React Native 调用原生Android组件

在如今的App中,已经有成千上万的原生UI部件了--其中的一些是平台的一部分,另一些可能来自于一些第三方库,而且可能你自己还收藏了很多.React Native已经封装了大部分最常见的组件,譬如ScrollView和TextInput,但不可能封装全部组件.而且,说不定你曾经为自己以前的App还封装过一些组件,React Native肯定没法包含它们.幸运的是,在React Naitve应用程序中封装和植入已有的组件非常简单. 比如WebView,官方并没有提供Android端的实现,那么我们现

react native 使用 iOS 原生 UI 组件

目前 react native 的组件还是不多,有些也并不怎么好用,这时候就需要封装原生 UI 组件了 之前写过RN 与 native 的通信 无非就是两种: 1>>>  react native 内部事件需要通知 native 调用 native 的方法(或者传递RN 中的数据到 native),这时候可以用新建一个 manager 之类的文件 RCT_EXPORT_MOUDLE() 暴露 native类  ,RCT_EXPORT_METHOD () 暴露 native 方法给 js

Android React Native组件的生命周期及回调函数

熟悉android的童鞋应该都清楚,android是有生命周期的,其很多组件也是有生命周期.今天小编和大家分享的React Native组件的生命周期,还不了解的童鞋,赶紧来围观吧 在android开发中,React Native组件的生命周期,大致分为三个阶段,分别是: 1.组件第一次绘制阶段,这个阶段主要是组件的加载和初始化: 2.组件在运行和交互阶段,这个阶段组件可以处理用户交互,或者接收事件更新界面: 3.组件卸载消亡的阶段,这个阶段主要是组件的清理工作. 在Android React

Android React Native组件的生命周期

和Android一样,React的组件也有对应的生命周期.Android React Native组件的生命周期可以总的概括为下面这一张图. 可以把组件生命周期大致分为三个阶段: 第一阶段:是组件第一次绘制阶段,如图中的上面虚线框内,在这里完成了组件的加载和初始化: 第二阶段:是组件在运行和交互阶段,如图中左下角虚线框,这个阶段组件可以处理用户交互,或者接收事件更新界面: 第三阶段:是组件卸载消亡的阶段,如图中右下角的虚线框中,这里做一些组件的清理工作. 生命周期回调函数总共有10个. obje

React Native iOS原生模块开发实战|教程|心得|如何创建React Native iOS原生模块

尊重版权,未经授权不得转载 本文出自:贾鹏辉的技术博客(http://blog.csdn.net/fengyuzhengfan/article/details/54691432) 前言 一直想写一下我在React Native原生模块封装方面的一些经验和心得,来分享给大家,但实在抽不开身,今天看了一下日历发现马上就春节了,所以就赶在春节之前将这篇博文写好并发布(其实是两篇:要看Android篇的点这里<React Native Android原生模块开发>). 我平时在用React Nativ

Android React Native 开发环境搭建---windows下

环境搭建 环境搭建可以参考RN官网,也可以参考中文版本:http://reactnative.cn/docs/0.45/getting-started.html 如果你希望可以看到原版的安装流程,可以看官方的地址,本文只是我个人的实践,并且仅限于window平台. 官方的地址:https://facebook.github.io/react-native/docs/getting-started.html 1.下载Chocolatey 去官网下载,一般没有问题. 2.Node,python2,j

【React Native开发】React Native移植原生Android项目

转载请标明出处: http://blog.csdn.net/developer_jiangqq/article/details/50519677 本文出自:[江清清的博客] (一)前言 [好消息]个人网站已经上线运行,后面博客以及技术干货等精彩文章会同步更新,请大家关注收藏:http://www.lcode.org 前三节课程我们已经对于React Native For Android的环境搭建,IDE安装配置以及应用运行,调试相关的知识点做了讲解.今天我们来讲一个非常有用的知识点.移植我们已有