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

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



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


布局代码如下:

          <Animated.View style={[styles.tip , {transform: [{
                translateY: this.state.offset.interpolate({
                 inputRange: [0, 1],
                 outputRange: [height, (height-aHeight)]
                }),
              }]
            }]}>
            <View style={styles.tipTitleView} >
              <Text style={styles.cancelText} onPress={this.cancel.bind(this)}>取消</Text>
              <Text style={styles.okText} onPress={this.ok.bind(this)} >确定</Text>
            </View>
            <Picker
              style={styles.picker}
              mode={Picker.MODE_DIALOG}
              itemStyle={styles.itempicker}
              selectedValue={this.state.choice}
              onValueChange={choice => this.setState({choice: choice})}>
                {this.options.map((aOption) =>  <Picker.Item color='#b5b9be' label={aOption} value={aOption} key={aOption} /> )}
            </Picker>
          </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、布局效果见本文开始处


源码如下:

'use strict';
import React, { Component } from 'react';
import {
  StyleSheet,
  View,
  Image,
  Text,
  TouchableHighlight,
  Animated,
  Easing,
  Dimensions,
  Picker,
  TouchableOpacity,
} from 'react-native';

const {width, height} = Dimensions.get('window');
const navigatorH = 64; // navigator height
const [aWidth, aHeight] = [width, 214];
const [left, top] = [0, 0];

const styles = StyleSheet.create({
  container: {
    position:"absolute",
    width:width,
    height:height,
    left:left,
    top:top,
  },
  mask: {
    justifyContent:"center",
    backgroundColor:"#383838",
    opacity:0.8,
    position:"absolute",
    width:width,
    height:height,
    left:left,
    top:top,
  },
  tip: {
    width:aWidth,
    height:aHeight,
    // left:middleLeft,
    backgroundColor:"#fff",
    alignItems:"center",
    justifyContent:"space-between",
  },
  tipTitleView: {
    height:53,
    width:aWidth,
    flexDirection:'row',
    alignItems:'center',
    justifyContent:'space-between',
    borderBottomWidth:0.5,
    borderColor:"#f0f0f0",

  },
  cancelText:{
    color:"#e6454a",
    fontSize:16,
    paddingLeft:30,
  },
  okText:{
    color:"#e6454a",
    fontSize:16,
    paddingRight:27,
    fontWeight:'bold',
  },
  picker:{
    justifyContent:'center',
    // height: 216,//Picker 默认高度
    width:aWidth,
  },
  itempicker:{
    color:'#e6454a',
    fontSize:19,
    height:161
  }
});

export default class PickerWidget extends Component {

  constructor(props) {
    super(props);
    this.state = {
      offset: new Animated.Value(0),
      opacity: new Animated.Value(0),
      choice:this.props.defaultVal,
      hide: true,
    };
    this.options = this.props.options;
    this.callback = function () {};//回调方法
    this.parent ={};
  }

  componentWillUnMount(){
    this.timer && clearTimeout(this.timer);
  }

  render() {
    if(this.state.hide){
      return (<View />)
    } else {
      return (
        <View style={styles.container} >
          <Animated.View style={ styles.mask } >
          </Animated.View>

          <Animated.View style={[styles.tip , {transform: [{
                translateY: this.state.offset.interpolate({
                 inputRange: [0, 1],
                 outputRange: [height, (height-aHeight)]
                }),
              }]
            }]}>
            <View style={styles.tipTitleView} >
              <Text style={styles.cancelText} onPress={this.cancel.bind(this)}>取消</Text>
              <Text style={styles.okText} onPress={this.ok.bind(this)} >确定</Text>
            </View>
            <Picker
              style={styles.picker}
              mode={Picker.MODE_DIALOG}
              itemStyle={styles.itempicker}
              selectedValue={this.state.choice}
              onValueChange={choice => this.setState({choice: choice})}>
                {this.options.map((aOption) =>  <Picker.Item color='#b5b9be' label={aOption} value={aOption} key={aOption} /> )}
            </Picker>
          </Animated.View>
        </View>
      );
    }
  }

  componentDidMount() {
  }

  //显示动画
  in() {
    Animated.parallel([
      Animated.timing(
        this.state.opacity,
        {
          easing: Easing.linear,
          duration: 500,
          toValue: 0.8,
        }
      ),
      Animated.timing(
        this.state.offset,
        {
          easing: Easing.linear,
          duration: 500,
          toValue: 1,
        }
      )
    ]).start();
  }

  //隐藏动画
  out(){
    Animated.parallel([
      Animated.timing(
        this.state.opacity,
        {
          easing: Easing.linear,
          duration: 500,
          toValue: 0,
        }
      ),
      Animated.timing(
        this.state.offset,
        {
          easing: Easing.linear,
          duration: 500,
          toValue: 0,
        }
      )
    ]).start();

    this.timer = setTimeout(
      () => this.setState({hide: true}),
      500
    );
  }

  //取消
  cancel(event) {
    if(!this.state.hide){
      this.out();
    }
  }

  //选择
  ok() {
    if(!this.state.hide){
      this.out();
      this.callback.apply(this.parent,[this.state.choice]);
    }
  }

  show(obj:Object,callback:Object) {
    this.parent = obj;
    this.callback = callback;
    if(this.state.hide){
      this.setState({ hide: false}, this.in);
    }
  }
}


你可能感兴趣的:(Picker,ReactNative)