使用React Native封装原生手势解锁组件

(前言)

例子的Demo在这里由于本人工 (不) 作 (会) 忙 (Android开发),因此下文中的原生组件以iOS为例,Android原生组件也会考虑在后面补上。(本组件支持npm

由于篇幅的原因,本文不作React Native的环境搭建和如何创建项目的介绍(我没有前端开发经历哦,相信这点起步也同样难不倒你的),尚未了解的朋友可以参考以下介绍。文中的例子参考了React Native 官网的原文例子,原谅我手笨,尽管有公司前端同事的大力相助,这个小Demo依然做的磕磕碰碰,Anyway,在经过了两个晚上的不懈努力之后,我完成了预定目标,学到了不少有用的东西。对于这些我决定将自己的总结和教训分享出来,方便大家的学习,促进技术交流。

如何搭建React Native环境

React-Native开发的相关知识了解,前端开发的基本概念入门,包括框架介绍,控件布局,样式,网络请求,更多资源参考

为什么要做原生组件的封装呢?React Native为我们提供了很多现成组件,比如ScrollView,Navigator,TextInput;但是在实际开发中,我们许多时候中会遇到React Native没有为我们备好的组件的需求,而原生项目中已经有在用的控件了,后者往往来自于第三方库或者App自带。如果能把这些控件用JS封装好,并应用于React Native项目中,在性能上要优于后者,体验也更流畅;而React Native为我们提供了这样的入口,这是非常好的。

(一些有用的接口)

//RCTGestureViewManager.m
/**

RCT_EXPORT_MODULE(): 将本组件放入模块中方便JS的导入,在原生中它就是class
RCT_EXPORT_METHOD(): 将一些方法导出,方便JS调用。这个宏的参数中包括JS方法名,方法的参数。参数支持 string,
number, bool, function等JS类型
RCT_EXPORT_VIEW_PROPERTY(): 属性导出给JS,参数为属性的名称和类型。代码如下:

*/

//export modules methods and properties
RCT_EXPORT_MODULE() //default name is RNGesutreView

RCT_EXPORT_VIEW_PROPERTY(onComplete, RCTBubblingEventBlock)
RCT_EXPORT_VIEW_PROPERTY(nodeScale, CGFloat)
RCT_EXPORT_VIEW_PROPERTY(colCount, int)
RCT_EXPORT_VIEW_PROPERTY(backgroundImgName, NSString)

RCT_EXPORT_METHOD(setupNodeUI:(NSDictionary *)params) {
  NSString *nodeNormalImg = params[@"nodeNormal"];
  NSString *nodeErrorImg = params[@"nodeError"];
  NSString *nodeSelectImg = params[@"nodeSelect"];
  self.innerView.nodeErrorImgName = nodeErrorImg;
  self.innerView.nodeNormalImgName = nodeNormalImg;
  self.innerView.nodeSelectedImgName = nodeSelectImg;
}

为了方便UI组件和JS的交互,我们创建了RCTGestureViewManager,作为原生组件的代理,负责将组件的属性,方法,组件类导出给JS,向JS发送事件,并接收后者的回调,方法调用。RCTGestureViewManager需要继承于RCTViewManager,相应的部分JS代码则是:

//RCTGestureView.ios.js

const GestureManager = NativeModules.RNGestureViewManager
const NativeGestureView = requireNativeComponent('RNGestureView', RNGestureView);
export default class RNGestureView extends Component {

    _onGestureComplete(event) {
        if (!this.props.onGestureComplete) {
            return;
        }
        this.props.onGestureComplete(event.nativeEvent.completion)
    }

    componentDidMount() {
        if (this.props.nodeThemes) {
            GestureManager.setupNodeUI(this.props.nodeThemes);
        }
    }

    static propTypes = {
        nodeScale: PropTypes.number,
        colCount: PropTypes.number,
        onGestureComplete:PropTypes.func,
        backgroundImgName:PropTypes.string,
        nodeThemes: PropTypes.shape({
            nodeNormal: PropTypes.string,
            nodeError: PropTypes.string,
            nodeSelect: PropTypes.string
        })
    }

    render() {
        return (
            <NativeGestureView 
            {...this.props} onComplete = {this._onGestureComplete.bind(this)}/>
            //(event)=>this.props.onGestureComplete(event.nativeEvent.completion)
        );
    }
}

其中,onComplete是原生组件暴露出来的调用 JS 完成特定事件的方法也就是OC中的回调 block,在手势解锁完成后,调用JS中的同名方法,并把手势连接的密码作为参数传递给 JS。

另外,原生暴露出来的属性和方法在JS代码中需要相应的列出。方便JS这边的封装组件和原生进行参照比对。其中的nodeScale等四个字段都是RCTGestureView同名属性propTypesRNGestureView的类成员,负责完成以上的工作。

为了检验封装是否成功,我们进行简单的测试,测试的部分代码如下:

//index.ios.js

class gestureUnlock extends Component {
  constructor() {
    super()
    this.state= {
      textContent: 'test for callback from native module'
    }
  }
  componentDidMount() {
    GestureViewManager.setupNodeUI({
      nodeNormal: 'gesture_node_normal',
      nodeSelect: 'gesture_node_highlighted'
    });
  }
  render() {
    return (
      <View style={styles.container}>
        <GestureView style={styles.gesture} nodeScale={74} colCount={3} 
        backgroundImgName='Home_refresh_bg' onGestureComplete={(result)=>{
          console.log('result', result);
          this.setState({
          textContent:result==null? 'callback failed':result
        })}}/>
        <Text style={styles.passcode}>
          {this.state.textContent}
        </Text>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    backgroundColor: 'blue',
  },
  gesture:{
    flex: 1,
    justifyContent: 'center',
    // backgroundColor: 'yellow',
  },
  passcode: {
    fontSize: 20,
    textAlign: 'center', 
    margin: 10,
    color: 'white'
  },
});

运行中和手势动作结束后的效果:


componentDidMount是声明周期方法,对React Native中的对象运行的生命周期感兴趣的朋友可以参考说明

(结束语)

在本例中,原生向JS发送事件是通过RCTBubblingEventBlock,这是封装好的可以在OC中使用的 block。当调用时,会调用JS中的同名方法。

另外一个发送事件的方法是使用eventDispatcher,并在JS代码中注册监听同名的事件。至于这两个方法在封装原生控件这一操作上哪个更好,我还没有得到适合的答案,希望对此熟悉的朋友可以告诉我。

在这里推荐一个不错的学习React Native的网站,收集了架构,数据流,应用状态的监听等资料介绍。

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

推荐阅读更多精彩内容