我有一个自定义下拉菜单,其中下拉视图绝对定位。当组件直接位于滚动视图内部时,我将无法执行文本输入和可触摸操作。
自定义组件代码:
import React, { Component } from 'react';
import { View, Text, StyleSheet, TouchableOpacity, ScrollView, TextInput } from 'react-native';
import Icon_Feather from 'react-native-vector-icons/Feather';
import Icon_MaterialIcons from 'react-native-vector-icons/MaterialIcons';
import PropTypes from 'prop-types';
import _ from 'lodash';
let dropDownData = []
class MultiSelectDropdown extends Component {
constructor(props) {
super(props);
this.state = {
isVisible: false,
data: [],
searchData: [],
selectedData: [],
// selectAllStatus: false,
searchableText: null,
defaultSelectedValues: ''
}
}
UNSAFE_componentWillReceiveProps = async (props) => {
await this.setState({
data: props.data,
defaultSelectedValues: props.selectedData != undefined ? props.selectedData : [],
isVisible: props.isVisible
})
// alert(this.state.data)
await this.formatReceivedData()
}
formatReceivedData = async () => {
var pushedData = []
let tempData = JSON.parse(JSON.stringify(this.state.data))
tempData.forEach(element => {
let obj = element
Object.assign(obj, { selected: false })
pushedData.push(obj)
});
await this.setState({
selectedData: pushedData,
searchData: pushedData,
})
if (this.state.defaultSelectedValues.length > 0)
await this.checkDefaultValues();
}
checkDefaultValues = async () => {
this.state.data.forEach((ele1, index1) => {
this.state.defaultSelectedValues.forEach((ele2, index2) => {
if (_.isEqual(ele1, ele2)) {
this.state.selectedData[index1].selected = true
this.setState({
selectedData: this.state.selectedData
})
}
});
});
}
getLayout(layout) {
this.setState({
top: layout.height - 1
});
}
toggle() {
// this.setState({
// isVisible: ! this.state.isVisible,
// }, () => {
// const isVisible = this.state.isVisible;
// // if (isVisible) {
// // this.props.onOpen();
// // } else {
// // this.props.onClose();
// // }
// });
this.setState({
isVisible: !this.state.isVisible,
})
}
selectItem = async (data, index) => {
var tempSelectedData = this.state.selectedData
if (tempSelectedData[index].selected == false)
tempSelectedData[index].selected = true
else
tempSelectedData[index].selected = false
var truePropertyData = tempSelectedData.filter((item) => {
return item.selected != false
})
if (truePropertyData.length > this.props.maxItemsToSelect) {
// max
tempSelectedData[index].selected = false;
var truePropertyData1 = tempSelectedData.filter((item) => {
return item.selected!= false
})
this.removeExtraAddedProperty(truePropertyData1, index);
} else {
this.setState({
selectedData: tempSelectedData,
// selectAllStatus: false
})
this.removeExtraAddedProperty(truePropertyData, index);
}
}
getSelectedItemCount = () => {
var truePropertyData = this.state.selectedData.filter((item) => {
return item.selected!= false
})
return truePropertyData;
}
getLabelDisplayText = () => {
let count = this.getSelectedItemCount().length;
return this.props.multipleDataSelectedText.replace('%d', count);
}
selectAll = async () => {
var tempSelectedData = JSON.parse(JSON.stringify(this.state.selectedData))
var status = await this.selectAllOrUnselect()
// if (this.state.selectAllStatus) {
if (status) {
tempSelectedData.forEach((ele, i) => {
tempSelectedData[i].selected= false
});
this.setState({
selectedData: tempSelectedData,
// selectAllStatus: false
})
var truePropertyData = tempSelectedData.filter((item) => {
return item.selected!= false
})
this.removeExtraAddedProperty(truePropertyData, 0)
} else {
tempSelectedData.forEach((ele, i) => {
tempSelectedData[i].selected= true
});
this.setState({
selectedData: tempSelectedData,
// selectAllStatus: true
})
this.removeExtraAddedProperty(this.state.selectedData, 0)
}
}
removeExtraAddedProperty = (truePropertyData, index) => {
let tempTruePropertyData = JSON.parse(JSON.stringify(truePropertyData))
var actualData = []
if (tempTruePropertyData.length > 0) {
tempTruePropertyData.forEach(element => {
var obj = element
delete obj['selected']
actualData.push(obj)
});
} else
this.props.onItemChange(truePropertyData, index)
this.props.onItemChange(actualData, index)
}
selectAllOrUnselect = () => {
var returnStatus;
var trueFilteredData = this.state.selectedData.filter((item, i) => {
return item.selected == true
})
if (trueFilteredData.length == this.state.selectedData.length)
returnStatus = true
else
returnStatus = false
return returnStatus;
}
updateSearch = async (text) => {
await this.setState({
searchableText: text
})
let toSearch = (this.state.searchableText).toLowerCase();
let result = this.state.data.filter(o => o[this.props.displayLabel].toLowerCase().includes(toSearch));
await this.setState({
searchData: result
})
}
render() {
return (
<View style={[this.props.containerStyle, {
...(Platform.OS !== 'android' && {
zIndex: this.props.zIndex
})
}]}>
<TouchableOpacity
onLayout={(event) => this.getLayout(event.nativeEvent.layout)}
onPress={() => this.toggle()}
activeOpacity={1}
style={[
styles.dropDown,
this.props.style,
this.state.isVisible && styles.noBottomRadius, {
flexDirection: 'row', flex: 1
}
]}
>
<View style={[styles.dropDownDisplay]}>
{/* <Text style={[this.props.labelStyle, { flex: 1, marginRight: 5 }]}> */}
{/* {this.props.placeHolder} {this.getSelectedItemCount().length} */}
{/* {this.getSelectedItemCount().length > 0 ?
'Under Test'
:
JSON.stringify(this.state.placeHolder)
} */}
{/* </Text> */}
{this.getSelectedItemCount().length > 0 ?
<Text style={[this.props.labelStyle, { flex: 1, marginRight: 5 }]}>
{this.getLabelDisplayText()}
</Text>
:
<Text style={[this.props.labelStyle, { flex: 1, marginRight: 5 }]}>
{this.props.placeHolder} {JSON.stringify(this.state.isVisible)}
</Text>
}
</View>
<View style={[styles.arrow]}>
{!this.state.isVisible ?
<Icon_Feather name="chevron-down" size={15} color={'black'} />
:
<Icon_Feather name="chevron-up" size={15} color={'black'} />
}
</View>
</TouchableOpacity>
<View style={[
styles.dropDown,
styles.dropDownBox,
this.props.dropDownStyle,
!this.state.isVisible && styles.hidden, {
top: this.state.top,
maxHeight: this.props.dropDownMaxHeight,
zIndex: this.props.zIndex
}
]}>
{/* Search Text */}
<View style={{ width: '100%', flexDirection: 'row' }}>
<TextInput
style={[styles.input, this.props.searchableStyle]}
defaultValue={this.state.searchableText}
placeholder={this.props.searchablePlaceholder}
onChangeText={(text) => this.updateSearch(text)}
/>
</View>
<ScrollView style={{ width: '100%' }} nestedScrollEnabled={true}>
{this.state.searchData.length > 0 ? this.state.searchData.map((item, index) => (
<View key={index}>
<TouchableOpacity
style={[styles.dropDownItem, this.props.itemStyle]}
onPress={() => this.selectItem(item, index)}
>
<View style={{ flexDirection: 'row' }}>
<View style={{ paddingRight: 5 }}>
{(this.state.selectedData[index] != undefined && this.state.selectedData[index].selected == true) ?
<Icon_MaterialIcons name={'check-box'} size={22} color={'black'} />
:
<Icon_MaterialIcons name={'check-box-outline-blank'} size={22} color={'black'} />
}
</View>
<View style={{ justifyContent: 'center', alignItems: 'center' }}>
<Text style={[this.props.labelStyle]}>
{item[this.props.displayLabel]}
</Text>
</View>
</View>
</TouchableOpacity>
</View>
))
:
<Text>
Not Found
</Text>
}
</ScrollView>
</View>
</View >
);
}
}
MultiSelectDropdown.defaultProps = {
containerStyle: {},
style: {},
zIndex: 5000,
placeHolder: 'Select an option',
labelStyle: {},
dropDownStyle: {},
dropDownMaxHeight: 250,
itemStyle: {},
displayLabel: '',
searchableStyle: {},
searchablePlaceholder: 'Search',
multipleDataSelectedText: '%d items have been selected',
data: PropTypes.array.isRequired,
maxItemsToSelect: '',
isVisible: false,
selectAllText: 'Select All',
unselectAllText: 'Un-Select All'
}
MultiSelectDropdown.propTypes = {
containerStyle: PropTypes.object,
style: PropTypes.object,
zIndex: PropTypes.number,
placeHolder: PropTypes.string,
labelStyle: PropTypes.object,
dropDownStyle: PropTypes.object,
dropDownMaxHeight: PropTypes.number,
itemStyle: PropTypes.object,
displayLabel: PropTypes.string,
searchableStyle: PropTypes.object,
isVisible: PropTypes.bool,
searchablePlaceholder: PropTypes.string,
selectedData: PropTypes.any,
multipleDataSelectedText: PropTypes.string,
maxItemsToSelect: PropTypes.string,
selectAllText: PropTypes.string,
unselectAllText: PropTypes.string
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'white',
},
noBottomRadius: {
borderBottomLeftRadius: 0,
borderBottomRightRadius: 0,
},
dropDown: {
paddingHorizontal: 10,
paddingVertical: 5,
backgroundColor: '#fff',
borderTopRightRadius: 5,
borderTopLeftRadius: 5,
borderBottomRightRadius: 5,
borderBottomLeftRadius: 5,
borderWidth: 1,
borderColor: '#dfdfdf',
},
dropDownDisplay: {
flexDirection: 'row',
alignItems: 'center',
borderTopRightRadius: 0,
borderBottomRightRadius: 0,
flexGrow: 1
},
arrow: {
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
textAlign: 'center',
paddingVertical: 8,
borderTopLeftRadius: 0,
borderBottomLeftRadius: 0,
},
dropDownBox: {
borderTopLeftRadius: 0,
borderTopRightRadius: 0,
alignItems: 'center',
justifyContent: 'center',
textAlign: 'center',
position: 'absolute',
width: '100%',
zIndex: 1
},
hidden: {
position: 'relative',
display: 'none',
borderWidth: 0
},
dropDownItem: {
paddingVertical: 8,
width: '100%',
justifyContent: 'center'
},
input: {
flex: 1,
borderColor: '#dfdfdf',
borderBottomWidth: 1,
paddingHorizontal: 0,
paddingVertical: 8,
marginBottom: 2,
},
});
export default MultiSelectDropdown;
上面的组件在视图中使用时可以正常工作,但是当将其放置在模式中时则无法工作。即我无法执行触摸和文本输入操作。