react-native-dropdownmenus
Version:
<img height="600" width="300" src="https://raw.githubusercontent.com/pengweiqiang/ReactNative-DropDownMenu/master/screenShot/demo.png" align=center />
283 lines (252 loc) • 10 kB
JavaScript
/**
* @Date: 2019-01-11
* @Author pengweiqiang
* @Project DropDownMenu
* @Description
*/
'use strict';
import React, {Component} from 'react';
import {
View,
Text,
TouchableHighlight,
Image,
TouchableOpacity,
ScrollView,
Animated,
Easing,
StyleSheet,
PixelRatio
} from 'react-native';
import PropTypes from 'prop-types';
const LINE = 1 / PixelRatio.get();
class DropdownMenu extends Component {
constructor(props, context) {
super(props, context);
let selectIndex = this.props.selectIndex;
if(selectIndex === undefined){
selectIndex = new Array(this.props.data.length);
for (let i = 0; i < selectIndex.length; i++) {
selectIndex[i] = 0;
}
}
// console.log(this.props.maxHeight);
if(selectIndex.length !== this.props.data.length){
throw new Error("selectIndex length is not equals data length");
}
this.state = {
activityIndex: -1,
selectIndex: selectIndex,
rotationAnims: props.data.map(() => new Animated.Value(0))
};
this.defaultConfig = {
bgColor: 'grey',
tintColor: '#333333',
activityTintColor: "red",
arrowImg: require('../images/dropdown_arrow.png'),
checkImage: require('../images/menu_check.png'),
};
}
renderChcek(index, title) {
var activityIndex = this.state.activityIndex;
if (this.state.selectIndex[activityIndex] === index) {
var checkImage = this.props.checkImage ? this.props.checkImage : this.defaultConfig.checkImage;
return (
<View style={{flex: 1, justifyContent: 'space-between', alignItems: "center", paddingHorizontal: 15, flexDirection: 'row'}} >
<Text
style={[
styles.item_text_style,
this.props.optionTextStyle,
{color: this.props.activityTintColor ? this.props.activityTintColor : this.defaultConfig.activityTintColor}
]} >
{title}
</Text>
<Image
source={checkImage}
style={{tintColor: this.props.activityTintColor ? this.props.activityTintColor : this.defaultConfig.activityTintColor}} />
</View>
);
} else {
return (
<View style={{flex: 1, justifyContent: 'space-between', alignItems: "center", paddingHorizontal: 15, flexDirection: 'row'}} >
<Text style={[
styles.item_text_style,
this.props.optionTextStyle,
{color: this.props.tintColor ? this.props.tintColor : this.defaultConfig.tintColor}
]} >{title}</Text>
</View>
);
}
}
renderActivityPanel() {
if (this.state.activityIndex >= 0) {
var currentTitles = this.props.data[this.state.activityIndex];
var heightStyle = {};
if (this.props.maxHeight && this.props.maxHeight < currentTitles.length * 44) {
heightStyle.height = this.props.maxHeight;
}
return (
<View style={{position: 'absolute', left: 0, right: 0, top: 41, bottom: 0}}>
<TouchableOpacity onPress={() => this.openOrClosePanel(this.state.activityIndex)} activeOpacity={1} style={{position: 'absolute', left: 0, right: 0, top: 0, bottom: 0}}>
<View style={{opacity: 0.4, backgroundColor: 'black', flex: 1 }} />
</TouchableOpacity>
<ScrollView style={[{position: 'absolute', top: 0, left: 0, right: 0, backgroundColor: 'white'}, heightStyle]} >
{
currentTitles.map((title, index) =>
<TouchableOpacity key={index} activeOpacity={1} style={{flex: 1, height: 44}} onPress={this.itemOnPress.bind(this, index)} >
{this.renderChcek(index, title)}
<View style={{backgroundColor: '#F6F6F6', height: 1, marginLeft: 15}} />
</TouchableOpacity>
)
}
</ScrollView>
</View>
);
} else {
return (null);
}
}
openOrClosePanel(index) {
this.props.bannerAction ? this.props.bannerAction() : null;
// var toValue = 0.5;
if (this.state.activityIndex == index) {
this.closePanel(index);
this.setState({
activityIndex: -1,
});
// toValue = 0;
} else {
if (this.state.activityIndex > -1) {
this.closePanel(this.state.activityIndex);
}
this.openPanel(index);
this.setState({
activityIndex: index,
});
// toValue = 0.5;
}
// Animated.timing(
// this.state.rotationAnims[index],
// {
// toValue: toValue,
// duration: 300,
// easing: Easing.linear
// }
// ).start();
}
openPanel(index) {
Animated.timing(
this.state.rotationAnims[index],
{
toValue: 0.5,
duration: 300,
easing: Easing.linear
}
).start();
}
closePanel(index) {
Animated.timing(
this.state.rotationAnims[index],
{
toValue: 0,
duration: 300,
easing: Easing.linear
}
).start();
}
itemOnPress(index) {
if (this.state.activityIndex > -1) {
var selectIndex = this.state.selectIndex;
selectIndex[this.state.activityIndex] = index;
this.setState({
selectIndex: selectIndex
});
if (this.props.handler) {
this.props.handler(this.state.activityIndex, index);
}
}
this.openOrClosePanel(this.state.activityIndex);
}
renderDropDownArrow(index) {
var icon = this.props.arrowImg ? this.props.arrowImg : this.defaultConfig.arrowImg;
return (
<Animated.Image
source={icon}
style={{
width:10,
height:6,
marginLeft: 8,
tintColor: (index === this.state.activityIndex) ? (this.props.activityTintColor ? this.props.activityTintColor : this.defaultConfig.activityTintColor) : (this.props.tintColor ? this.props.tintColor : this.defaultConfig.tintColor),
transform: [{
rotateZ: this.state.rotationAnims[index].interpolate({
inputRange: [0, 1],
outputRange: ['0deg', '360deg']
})
}]
}} />
);
}
render() {
return (
<View style={{flexDirection: 'column', flex: 1}} >
<View style={{
flexDirection: 'row',
borderTopWidth: LINE,
borderTopColor: '#bdbdbd',
borderBottomWidth: 1,
borderBottomColor: '#f2f2f2',
backgroundColor: this.props.bgColor ? this.props.bgColor : this.defaultConfig.bgColor}} >
{
this.props.data.map((rows, index) =>
<TouchableOpacity
activeOpacity={1}
onPress={this.openOrClosePanel.bind(this, index)}
key={index}
style={{flex: 1, height: 40, alignItems: "center", justifyContent: "center"}} >
<View style={{flexDirection: 'row', alignItems: "center", justifyContent: "center"}} >
<Text
style={[
styles.title_style,
this.props.titleStyle,
{color: (index === this.state.activityIndex) ?
(this.props.activityTintColor ? this.props.activityTintColor : this.defaultConfig.activityTintColor)
:
(this.props.tintColor ? this.props.tintColor : this.defaultConfig.tintColor)}
]} >
{rows[this.state.selectIndex[index]]}
</Text>
{this.renderDropDownArrow(index)}
</View>
</TouchableOpacity>
)
}
</View>
{this.props.children}
{this.renderActivityPanel()}
</View>
);
}
}
DropdownMenu.propTypes = {
bgColor: PropTypes.string,
tintColor: PropTypes.string,
activityTintColor: PropTypes.string,
arrowImg: PropTypes.number,
checkImage: PropTypes.number,
data: PropTypes.array,
bannerAction: PropTypes.func,
optionTextStyle: PropTypes.object,
titleStyle: PropTypes.object,
maxHeight: PropTypes.number
}
const styles = StyleSheet.create({
title_style: {
fontSize: 14
},
item_text_style: {
color: '#333333',
fontSize: 14,
marginLeft:15,
}
});
export default DropdownMenu;