React Native自定义控件【底部抽屉菜单】

一、需求分析


原生开发中,自定义View可谓是屡见不鲜的事情,往往系统的控件总不能满足现实的需求。五花八门的产品设计需要我们做出不同的View。关于自定义View的内容网上已经有很多的博文,本篇博客要和大家分享如何在React Native中自定义组件实现抽屉菜单控件效果。分享功能在App中的重要性想必是不言而喻的,那么RN中如何实现这种效果呢?

react Native 系统库中只提供了iOS的实现,即ActionSheetIOS.该控件的显示方式有两种实现:

(1)showActionSheetWithOptions

(2)showShareActionSheetWithOptions

第一种是在ios设备上显示一个ActionSheet弹出框。第二种实现是在iOS设备上显示一个分享弹出框。借用官方的图片说明如下:

React Native自定义控件【底部抽屉菜单】_第1张图片  React Native自定义控件【底部抽屉菜单】_第2张图片

IOS设备上的实现系统已经提供了,接下来我们就需要如何适配Android。在原生开发中,自定义View也是有基本的流程:

(1)自定义控件类,继承View或系统控件。

(2)自定义属性

(3)获取自定义属性,并初始化一系列工具类

(4)重写onMeasure方法,对控件进行测量

(5)如果是自定义布局,还需要重写onLayout进行布局

在React Native中自定义组件的思路基本和原生自定义相似。所以按照这个流程,我们一步步实现即可。


二、功能实现


1、自定义组件,实现Component

[html]  view plain  copy
  1. export default class AndroidActionSheet extends Component  

2、自定义属性

[html]  view plain  copy
  1. // 1.声明所需要的属性  
  2. static propTypes= {  
  3.     title: React.PropTypes.string, // 标题  
  4.     content: React.PropTypes.object, //  内容  
  5.     show: React.PropTypes.func, // 显示  
  6.     hide: React.PropTypes.func, // 隐藏  
  7. }  
[html]  view plain  copy
  1. constructor(props) {  
  2.     super(props);  
  3.     this.translateY = 150;  
  4.     this.state = {  
  5.         visible: false,  
  6.         sheetAnim: new Animated.Value(this.translateY)  
  7.     }  
  8.     this.cancel = this.cancel.bind(this);  
  9. }  

3、实现基本布局

[html]  view plain  copy
  1. /**  
  2. * Modal为最外层,ScrollView为内容层  
  3. */  
  4. render() {  
  5.         const { visible, sheetAnim } = this.state;  
  6.         return(  
  7.             <Modal  
  8.             visible={ visible }  
  9.             transparent={ true }  
  10.             animationType="none"  
  11.             onRequestClose={ this.cancel }  
  12.             >  
  13.             <View style={ styles.wrapper }>  
  14.                             <TouchableOpacity style={styles.overlay} onPress={this.cancel}>TouchableOpacity>  
  15.                     <Animated.View  
  16.                         style={[styles.bd, {height: this.translateY, transform: [{translateY: sheetAnim}]}]}>  
  17.                         { this._renderTitle() }  
  18.                         <ScrollView  
  19.                                             horizontal={ true }  
  20.                                             showsHorizontalScrollIndicator={ false }>  
  21.                             {this._renderContainer()}  
  22.                         ScrollView>  
  23.                     Animated.View>  
  24.                 View>  
  25.             Modal>  
  26.         )  
  27. }  

可以看到上面我们定义了基本的布局,布局中使用_renderTitle()方法来渲染标题部分,内容区域为ScrollView,并且为横向滚动,即当菜单项超过屏幕宽度时,可以横向滑动选择。在内部调用了renderContainer方法来渲染菜单:

[html]  view plain  copy
  1. /**  
  2. * 标题  
  3. */  
  4. _renderTitle() {  
  5.     const { title,titleStyle } = this.props;  
  6.     if (!title) {  
  7.         return null  
  8.     }  
  9.         // 确定传入的是不是一个React Element,防止渲染的时候出错  
  10.     if (React.isValidElement(title)) {  
  11.         return (  
  12.             <View style={styles.title}>{title}View>  
  13.         )  
  14.     }  
  15.     return (  
  16.         <Text style={[styles.titleText,titleStyle]}>{title}Text>  
  17.     )  
  18. }  
  19.   
  20. /**  
  21. * 内容布局  
  22. */  
  23. _renderContainer() {  
  24.         const { content } = this.props;  
  25.         return (  
  26.             <View style={styles.container}>  
  27.                 { content }  
  28.             View>  
  29.         )  
  30.     }  

当我们需要点击Modal,进行关闭时,还需要处理关闭操作,Modal并没有为我们提供外部关闭处理,所以需要我们单独实现,从布局代码中我们看到TouchableOpacity作为遮罩层,并添加了单机事件,调用cancel来处理:

[html]  view plain  copy
  1. /**  
  2.  * 控制Modal点击关闭,Android返回键关闭  
  3.  */  
  4.  cancel() {  
  5.     this.hide();  
  6. }  

4、自定义方法,对外调用

在外部我们需要控制控件的显示和隐藏,所以需要对外公开显示、关闭的方法:

[html]  view plain  copy
  1. /**  
  2.  * 显示  
  3.  */  
  4. show() {  
  5.     this.setState({visible: true})  
  6.     Animated.timing(this.state.sheetAnim, {  
  7.         toValue: 0,  
  8.         duration: 250  
  9.     }).start();  
  10. }  
[html]  view plain  copy
  1. /**  
  2.  * 隐藏  
  3.  */  
  4. hide() {  
  5.      this.setState({ visible: false })  
  6.      Animated.timing(this.state.sheetAnim, {  
  7.         toValue: this.translateY,  
  8.         duration: 150  
  9.      }).start();  
  10. }  

5、使用

[html]  view plain  copy
  1. <ActionSheet  
  2.   ref='sheet'  
  3.   title='分享'  
  4.   content={this._renderContent()}  
  5. />  

至此,我们自定义组件就完成了。整体来看,基本的原理还是很简单的,主要利用了自定义属性,传参,动画,就可以轻松的实现了。本篇博客重点不是为了让大家知道怎么去写出这个效果,而是让大家明白,当我们遇到一个需要自定义的实现时,该如何去一步步实现。


三、效果图




近甚忙,趁晚色清静,闲暇之余,分享之。

源码下载

转自http://blog.csdn.net/u013718120/article/details/73744581

你可能感兴趣的:(】)