《React-Native系列》40、刨根问底Picker组件

来源:互联网 发布:rbf神经网络 python 编辑:程序博客网 时间:2024/06/05 03:24

最近做一个需求,需求里需要实现一个类似Picker组件的效果,如下图所示,页面布局很简单,上面一个View 包含两个Text或者Touch*组件,下面放置一个Picker组件。



这个组件在app中已经存在,本来打算直接桥接native的,觉得这样基础的组件,还是使用RN的吧,这样就开始了我的Picker刨根之路。


布局代码如下:

[javascript] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. <Animated.View style={[styles.tip , {transform: [{  
  2.       translateY: this.state.offset.interpolate({  
  3.        inputRange: [0, 1],  
  4.        outputRange: [height, (height-aHeight)]  
  5.       }),  
  6.     }]  
  7.   }]}>  
  8.   <View style={styles.tipTitleView} >  
  9.     <Text style={styles.cancelText} onPress={this.cancel.bind(this)}>取消</Text>  
  10.     <Text style={styles.okText} onPress={this.ok.bind(this)} >确定</Text>  
  11.   </View>  
  12.   <Picker  
  13.     style={styles.picker}  
  14.     mode={Picker.MODE_DIALOG}  
  15.     itemStyle={styles.itempicker}  
  16.     selectedValue={this.state.choice}  
  17.     onValueChange={choice => this.setState({choice: choice})}>  
  18.       {this.options.map((aOption) =>  <Picker.Item color='#b5b9be' label={aOption} value={aOption} key={aOption} /> )}  
  19.   </Picker>  
  20. </Animated.View>  


那么问题来了,当我给Picker的style属性设置height为161的时候,发现Picker的高度确实是161,背景色为green,但是滚动轮的height确不是161,如下图所示:

在上面的一个View部分,还是可以点击Picker的item选项,当我点击取消和确定的时候,Picker.item还是可以点击,这是不是Picker的bug?  



我是先在iOS上实现的,后来了解,Picker在原生iOS中height系统默认是216,好像还不能修改,what ?

难道又要和UI妥协,让修改下height。有点...


好吧,还是看下RN的源码看看是怎么回事!

搜索找到PickerIOS 这个类。有问题多看看源码,绝大多数问题都可以在源码中找到答案!

发现下面2段代码:

代码片段1:



代码片段2:




看到这儿,似乎找到了我想要的答案。

Picker有如下两个属性:




那么想要实现我们的效果,设置itemStyle的属性,覆盖默认的height不就可以了吗。

经过实现,确实解决了问题,这里也说明系统默认的Picker的216的高度也是可以修改的。


该组件实现功能

1、动画效果,点击时,组件从手机下面弹出,有遮罩层

2、布局效果见本文开始处


源码如下:

[javascript] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. 'use strict';  
  2. import React, { Component } from 'react';  
  3. import {  
  4.   StyleSheet,  
  5.   View,  
  6.   Image,  
  7.   Text,  
  8.   TouchableHighlight,  
  9.   Animated,  
  10.   Easing,  
  11.   Dimensions,  
  12.   Picker,  
  13.   TouchableOpacity,  
  14. } from 'react-native';  
  15.   
  16. const {width, height} = Dimensions.get('window');  
  17. const navigatorH = 64; // navigator height  
  18. const [aWidth, aHeight] = [width, 214];  
  19. const [left, top] = [0, 0];  
  20.   
  21. const styles = StyleSheet.create({  
  22.   container: {  
  23.     position:"absolute",  
  24.     width:width,  
  25.     height:height,  
  26.     left:left,  
  27.     top:top,  
  28.   },  
  29.   mask: {  
  30.     justifyContent:"center",  
  31.     backgroundColor:"#383838",  
  32.     opacity:0.8,  
  33.     position:"absolute",  
  34.     width:width,  
  35.     height:height,  
  36.     left:left,  
  37.     top:top,  
  38.   },  
  39.   tip: {  
  40.     width:aWidth,  
  41.     height:aHeight,  
  42.     // left:middleLeft,  
  43.     backgroundColor:"#fff",  
  44.     alignItems:"center",  
  45.     justifyContent:"space-between",  
  46.   },  
  47.   tipTitleView: {  
  48.     height:53,  
  49.     width:aWidth,  
  50.     flexDirection:'row',  
  51.     alignItems:'center',  
  52.     justifyContent:'space-between',  
  53.     borderBottomWidth:0.5,  
  54.     borderColor:"#f0f0f0",  
  55.   
  56.   },  
  57.   cancelText:{  
  58.     color:"#e6454a",  
  59.     fontSize:16,  
  60.     paddingLeft:30,  
  61.   },  
  62.   okText:{  
  63.     color:"#e6454a",  
  64.     fontSize:16,  
  65.     paddingRight:27,  
  66.     fontWeight:'bold',  
  67.   },  
  68.   picker:{  
  69.     justifyContent:'center',  
  70.     // height: 216,//Picker 默认高度  
  71.     width:aWidth,  
  72.   },  
  73.   itempicker:{  
  74.     color:'#e6454a',  
  75.     fontSize:19,  
  76.     height:161  
  77.   }  
  78. });  
  79.   
  80. export default class PickerWidget extends Component {  
  81.   
  82.   constructor(props) {  
  83.     super(props);  
  84.     this.state = {  
  85.       offset: new Animated.Value(0),  
  86.       opacity: new Animated.Value(0),  
  87.       choice:this.props.defaultVal,  
  88.       hide: true,  
  89.     };  
  90.     this.options = this.props.options;  
  91.     this.callback = function () {};//回调方法  
  92.     this.parent ={};  
  93.   }  
  94.   
  95.   componentWillUnMount(){  
  96.     this.timer && clearTimeout(this.timer);  
  97.   }  
  98.   
  99.   render() {  
  100.     if(this.state.hide){  
  101.       return (<View />)  
  102.     } else {  
  103.       return (  
  104.         <View style={styles.container} >  
  105.           <Animated.View style={ styles.mask } >  
  106.           </Animated.View>  
  107.   
  108.           <Animated.View style={[styles.tip , {transform: [{  
  109.                 translateY: this.state.offset.interpolate({  
  110.                  inputRange: [0, 1],  
  111.                  outputRange: [height, (height-aHeight)]  
  112.                 }),  
  113.               }]  
  114.             }]}>  
  115.             <View style={styles.tipTitleView} >  
  116.               <Text style={styles.cancelText} onPress={this.cancel.bind(this)}>取消</Text>  
  117.               <Text style={styles.okText} onPress={this.ok.bind(this)} >确定</Text>  
  118.             </View>  
  119.             <Picker  
  120.               style={styles.picker}  
  121.               mode={Picker.MODE_DIALOG}  
  122.               itemStyle={styles.itempicker}  
  123.               selectedValue={this.state.choice}  
  124.               onValueChange={choice => this.setState({choice: choice})}>  
  125.                 {this.options.map((aOption) =>  <Picker.Item color='#b5b9be' label={aOption} value={aOption} key={aOption} /> )}  
  126.             </Picker>  
  127.           </Animated.View>  
  128.         </View>  
  129.       );  
  130.     }  
  131.   }  
  132.   
  133.   componentDidMount() {  
  134.   }  
  135.   
  136.   //显示动画  
  137.   in() {  
  138.     Animated.parallel([  
  139.       Animated.timing(  
  140.         this.state.opacity,  
  141.         {  
  142.           easing: Easing.linear,  
  143.           duration: 500,  
  144.           toValue: 0.8,  
  145.         }  
  146.       ),  
  147.       Animated.timing(  
  148.         this.state.offset,  
  149.         {  
  150.           easing: Easing.linear,  
  151.           duration: 500,  
  152.           toValue: 1,  
  153.         }  
  154.       )  
  155.     ]).start();  
  156.   }  
  157.   
  158.   //隐藏动画  
  159.   out(){  
  160.     Animated.parallel([  
  161.       Animated.timing(  
  162.         this.state.opacity,  
  163.         {  
  164.           easing: Easing.linear,  
  165.           duration: 500,  
  166.           toValue: 0,  
  167.         }  
  168.       ),  
  169.       Animated.timing(  
  170.         this.state.offset,  
  171.         {  
  172.           easing: Easing.linear,  
  173.           duration: 500,  
  174.           toValue: 0,  
  175.         }  
  176.       )  
  177.     ]).start();  
  178.   
  179.     this.timer = setTimeout(  
  180.       () => this.setState({hide: true}),  
  181.       500  
  182.     );  
  183.   }  
  184.   
  185.   //取消  
  186.   cancel(event) {  
  187.     if(!this.state.hide){  
  188.       this.out();  
  189.     }  
  190.   }  
  191.   
  192.   //选择  
  193.   ok() {  
  194.     if(!this.state.hide){  
  195.       this.out();  
  196.       this.callback.apply(this.parent,[this.state.choice]);  
  197.     }  
  198.   }  
  199.   
  200.   show(obj:Object,callback:Object) {  
  201.     this.parent = obj;  
  202.     this.callback = callback;  
  203.     if(this.state.hide){  
  204.       this.setState({ hide: false}, this.in);  
  205.     }  
  206.   }  
  207. }  

0 0
原创粉丝点击