[React Native]原生UI组件(上)

前面两篇文章主要介绍了如何在ReactNative中集成并使用原生模块的代码,本篇文章会讲解另一个和原生模块有关的重点内容,那就是在ReactNative中使用已有的原生UI组件。

总所周知,移动App快速发展的这几年,用户对于交互体验(UI、UE)的要求越来越高,因此,在原生开发中涌现了很多优秀的UI组件。ReactNative做为一个新的技术方向,目前在UI组件的积累难免还没有原生那么丰富和强大,所以我们必须要学会如何在ReactNative中使用一些我们已有的原生UI组件,并能和这些组件进行“交流”(数据、事件等)。

本文会演示如何在ReactNative中使用“仿QQ”滑动删除消息组件SwipeMenuListView,对这个控件不熟悉的朋友请先查看官方说明,本篇文章的最终效果图如下

device-2016-06-05-204355_0-76.gif

正如上图所演示的,使用原生UI会涉及到"数据""事件"两个部分,由于篇幅较长,我们会分成上下两篇文章讲解,本篇文章会讲解"数据"部分。

那么,下面我们将一步步演示如何实现上面这个图的效果

  • 步骤一:新建ReactNative项目

使用下面的命令新建一个ReactNative项目

react-native init Demo4

让我们运行下新建的项目,效果如下


Paste_Image.png
  • 步骤二:在原生项目中引入SwipeMenuListView

使用AndroidStudio打开Demo4目录下的android文件夹,打开app目录下的build.gradle文件,在dependencies节点中加入以下部分

compile 'com.baoyz.swipemenulistview:library:1.3.0'
  • 步骤三:导出原生视图SwipeMenuListView给JS模块使用

原生视图需要被ViewManager创建和管理,这样才能被JS模块使用。ViewManager是一个抽象的类,我们可以使用它的派生类SimpleViewManager来实现,另外SimpleViewManager还可以将我们的原生视图的属性导出给JS模块,这样我们在JS模块就可以传递数据给原生视图(或变量、属性等)来改变原生视图的样式和行为。

提供原生视图的步骤如下:

  1. 创建一个SimpleViewManager的子类AppViewManager
  2. 实现createViewInstance方法
  3. 导出视图的属性:使用@ReactProp注解来导出属性的设置方法
  4. 注册视图
  5. 实现JS模块

第4步与我们前面两篇文章讲解的的原生模块比较一致,原生模块和UI都需要注册才能使用,下面我们将详细介绍这5个步骤。

1. 创建一个SimpleViewManager的子类

...
public class AppViewManager extends SimpleViewManager<SwipeMenuListView> {    
  @Override  
  public String getName() {        
    return "SwipeMenuListView";    
  }

这个例子里我们创建一个视图管理类AppViewManager,它继承自SimpleViewManager<SwipeMenuListView>SwipeMenuListView是这个视图管理类所管理的对象类型,这应当是一个自定义的原生视图,getName方法会用于JS端引用这个原生视图。

2. 实现createViewInstance方法

...
@Override
protected SwipeMenuListView createViewInstance(final ThemedReactContext reactContext) {
    SwipeMenuListView swipeMenuListView = new SwipeMenuListView(reactContext);

    // set creator
    swipeMenuListView.setMenuCreator(initMenu(reactContext));

    return swipeMenuListView;
}

这里,我们直接new一个SwipeMenuListView,然后使用setMenuCreator方法设置菜单,我们写了一个initMenu方法来封装菜单的实现过程,由于这里不是本文介绍的重点,这里不做分析,有兴趣的朋友可以查看文章最后的源代码。

3. 导出视图的属性:使用@ReactProp注解来导出属性的设置方法
这里我们引用官方的说明:

要导出属性给JS使用,需要申明带有@ReactProp注解的设置方法。方法的第一个参数是要修改属性的视图实例,第二个参数是要设置的属性值。方法的返回值类型必须为void,而且访问控制必须被声明为public。JavaScript所得知的属性类型会由该方法第二个参数的类型来自动决定。支持的类型有:boolean, int, float, double, String, Boolean, Integer,ReadableArray, ReadableMap。

...
/**
 * 导出属性"array"给JS模块调用
 * @param swipeMenuListView
 * @param array
 */
@ReactProp(name = "array")
public void setDataSource(SwipeMenuListView swipeMenuListView, ReadableArray array)
{
    dataSource = new ArrayList<>();
    for(int i = 0; i < array.size(); i++)
    {
        dataSource.add(array.getString(i));
    }
    adapter = new MyAdapter(mContext, dataSource);
    swipeMenuListView.setAdapter(adapter);
}

这个方法做的事情很简单,主要是将ReadableArray类型的数据转换为我们熟知的ArrayList,然后使用MyAdapterSwipeMenuListView绑定一个数据源。MyAdapter也很简单,它的布局仅有一个TextView,这里不做分析。

4. 注册视图
在Java中的最后一步就是将视图控制器注册到应用中,和[React Native]原生模块(上)介绍的一样,我们需要新建一个class:ReactPackager,并且实现ReactPackage接口。不同的是,原生模块需要添加到createNativeModules中,而原生UI则需要添加到createViewManagers中。

...
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) {
      // 注册AppViewManager
      List<ViewManager> viewManagers = new ArrayList<>();
      viewManagers.add(new AppViewManager());
      return viewManagers;
  }
}

当然,AppReactPackage需要在MainActivitygetPackages中注册并返回。

...
@Override
protected List<ReactPackage> getPackages() {
    return Arrays.<ReactPackage>asList(
        new MainReactPackage(),
        new AppReactPackage()
    );
}

5. 实现JS模块
我们需要新建一个JS文件,来描述我们在AppViewManagergetName方法返回的SwipeMenuListView

'use strict';
var {
    PropTypes
} = require('react');
var {
    requireNativeComponent, View
} = require('react-native');

var iface = {
    name: 'SwipeMenuListView',
    propTypes: {
        array: PropTypes.arrayOf(PropTypes.string),
        ...View.propTypes,// 包含默认的View的属性
    },
};

module.exports = requireNativeComponent('SwipeMenuListView', iface);

requireNativeComponent通常接受两个参数:
第一个参数AppViewManagergetName方法返回的视图名称。
第二个参数是一个描述UI组件接口的对象,这个对象通常包括两个重要的部分:

  1. name:便于调试时显示(你可以设置为任意字符串)。
  1. propTypes:用来声明@ReactProp(name = "array")注解中array参数的JS类型,这里PropTypes.arrayOf(PropTypes.string)表示字符串类型的数组。另外...View.propTypes用来声明View的默认属性,记住这一个声明是必须的,否则你将无法正确使用原生UI。

最后,我们看下如何在JS模块使用这个原生UI

...
class Demo4 extends Component {
  render() {
    return (
      <View style={styles.container}>
        <SwipeMenuListView style={styles.listView} array={["Java", "C", "C++", "C#", "Python", "PHP"
              , "Visual Basic .NET", "JavaScript", "Assembly Language", "Ruby", "Perl"
              , "Delphi", "Visual Basic", "Swift", "MATLAB", "Pascal"]}>
        </SwipeMenuListView>
      </View>
    );
  }
}
...
AppRegistry.registerComponent('Demo4', () => Demo4);

这里需要说明的是,一定要指明SwipeMenuListView的高度和宽度,否则无法显示。

本文的源码地址Demo4

下一篇文章会介绍ReactNative与原生UI组件“事件”交互的内容,感兴趣的朋友请继续阅读[React Native]原生UI组件(下)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,053评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,527评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,779评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,685评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,699评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,609评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,989评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,654评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,890评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,634评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,716评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,394评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,976评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,950评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,191评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,849评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,458评论 2 342

推荐阅读更多精彩内容