React Native中TouchableHighlight点击后背景颜色切换失效求助
问题分析与解决方案
你的问题核心在于所有列表项共用了同一个pressed状态,而且错误地使用了onShowUnderlay/onHideUnderlay来控制持久选中状态——这两个回调只是在按下/松开组件时触发临时状态,松开后就会重置,无法实现点击后保持颜色的效果。另外,单个布尔值无法区分多个列表项的选中状态,导致所有项会同时变化。
下面是修复后的完整代码,我做了针对性的优化,同时保留了你原本的需求逻辑:
import React, { Component } from 'react'; import { StyleSheet, Text, StatusBar , TouchableOpacity, View, FlatList, ActivityIndicator, TouchableHighlight, PropTypes, Image, Alert } from 'react-native'; import Logo from '../components/Logo'; import Form from '../components/Front'; import {Actions} from 'react-native-router-flux'; export default class Login extends Component<{}> { constructor() { super(); this.state = { dataSource: [], selectedNumbers: [] // 存储选中的数字ID,替代原有的单个pressed状态 }; } izijackpotconfirm() { Actions.izijackpotconfirm() } componentDidMount() { let items = Array.apply(null, Array(25)).map((v, i) => { return { id: i+1 }; }); this.setState({ dataSource: items, }); } static navigationOptions = { title: "Izi Jackpot", headerStyle: { backgroundColor: "#354247" }, headerTintColor: "#fff", headerTitleStyle: { fontWeight: "bold" } }; // 切换单个数字的选中状态,同时限制最多选5个 toggleNumberSelection = (numberId) => { this.setState(prevState => { let newSelected = [...prevState.selectedNumbers]; if (newSelected.includes(numberId)) { // 已选中则移除 newSelected = newSelected.filter(id => id !== numberId); } else { // 未选中则添加,同时判断是否超过5个上限 if (newSelected.length < 5) { newSelected.push(numberId); } else { Alert.alert("提示", "最多只能选择5个数字"); } } return { selectedNumbers: newSelected }; }); } render() { return( <View style={styles.container}> <View style={styles.middlecontainer}> <Text style={styles.logoText}>Please Select 5 Numbers and Submit</Text> </View> <FlatList data={this.state.dataSource} renderItem={({ item }) => { // 判断当前数字是否被选中 const isSelected = this.state.selectedNumbers.includes(item.id); return ( <View style={{ flex: 1, flexDirection: 'column', margin: 1 }}> <TouchableHighlight onPress={() => this.toggleNumberSelection(item.id)} style={[ styles.iziPizi, isSelected ? styles.iziPiziPress : {} // 根据选中状态切换样式 ]} underlayColor={'gray'} // 保留按下时的临时高亮反馈 > <Text style={styles.buttonText}>{ item.id}</Text> </TouchableHighlight> </View> ) }} numColumns={5} keyExtractor={(item, index) => index.toString()} /> <View style={styles.middlecontainer}> <TouchableOpacity style={styles.button} onPress={this.izijackpotconfirm} disabled={this.state.selectedNumbers.length !==5} // 未选满5个时禁用提交按钮 > <Text style={styles.buttonText}>Submit</Text> </TouchableOpacity> </View> </View> ) } } const styles = StyleSheet.create({ container : { backgroundColor:'#6F9000', justifyContent: 'center', flex: 1, paddingTop: 30, }, middlecontainer: { textAlign: 'center', alignItems: 'center', justifyContent :'center', flex:1 }, signupTextCont : { flexGrow: 1, alignItems:'flex-end', justifyContent :'center', paddingVertical:16, flexDirection:'row' }, signupText: { color:'rgba(255,255,255,0.6)', fontSize:16 }, signupButton: { color:'#ffffff', fontSize:16, fontWeight:'500' }, iziPizi: { width: 55, padding: 15, margin: 5, borderRadius: 80, borderWidth: 2, borderColor: '#FFFFFF', flex:1, backgroundColor: 'transparent' // 默认透明背景 }, iziPiziPress: { width: 55, padding: 15, margin: 5, backgroundColor:'#1c313a', borderRadius: 80, borderWidth: 2, borderColor: '#FFFFFF', flex:1 }, button: { width:300, backgroundColor:'#1c313a', borderRadius: 25, marginVertical: 10, paddingVertical: 13, opacity: 0.8 // 禁用时降低透明度提示用户 }, buttonText: { fontSize:16, fontWeight:'500', color:'#ffffff', textAlign:'center' }, logoText : { color:'#FFFFFF', fontSize: 16, fontWeight: '500', alignItems: 'center', justifyContent:'center', }, imageThumbnail: { justifyContent: 'center', alignItems: 'center', height: 100, }, });
关键修改说明
- 状态管理优化:用
selectedNumbers数组替代单个pressed布尔值,每个数字的选中状态独立存储,彻底解决了所有项同时变化的问题。 - 选中逻辑调整:通过
toggleNumberSelection方法处理点击事件,实现选中/取消选中的切换,同时添加了最多选5个的限制(符合需求里的"Select 5 Numbers"提示)。 - 样式应用修正:渲染每个项时,根据
isSelected判断是否应用选中样式,实现点击后持久保持背景色的效果。 - 用户体验提升:添加了提交按钮的禁用逻辑,未选满5个时按钮不可点击,同时给出弹窗提示,避免无效操作。
内容的提问来源于stack exchange,提问作者Ranjit
相关产品推荐
相关产品推荐

