I'm working on a React Native app with a typeahead component. The typeahead displays options that overlay other content on the route (see right image below). When a user clicks one of those options, an onPress listener runs a function:
This all works just fine on iOS. On Android though, the onPress event is never received. Even more strangely, when I try to click on an option lower in the list (like Boston, MA, USA), the onPress event is received by the card below the pressed option (Djerba).
Does anyone know what might cause this behavior? I'd be super grateful for any insights others can offer on this query.
Here's the code for the Explore view and the typeahead components.
Explore.js
import React from 'react'
import { connect } from 'react-redux'
import { Text, View, ScrollView, TouchableOpacity } from 'react-native'
import { gradients, sizing } from '../../style'
import { LinearGradient } from 'expo-linear-gradient'
import { MountainHero } from '../Heros'
import { CardRow } from '../Card'
import Loading from '../Loading'
import { setExploreSearch, onExploreTypeaheadClick } from '../../actions/locations'
import { Typeahead } from '../Typeahead'
const styles = {
container: {
flex: 1,
flexDirection: 'column',
},
scrollView: {
paddingBottom: sizing.margin,
},
loadingContainer: {
position: 'absolute',
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
zIndex: 100,
elevation: 100,
top: 53,
width: '100%',
},
typeahead: {
margin: sizing.margin,
marginBottom: 0,
width: sizing.screen.width - (2*sizing.margin),
zIndex: 100,
elevation: 100,
}
}
const Explore = props => {
const { authenticated: a, spotlight, loading } = props;
let r = (a.recommendedLocations || []);
if (!r || !spotlight) return null;
// remove spotlight locations from the recommended locations
const ids = spotlight.map(i => i.guid);
const recommended = r.filter(i => ids.indexOf(i.guid) == -1);
return (
<LinearGradient style={styles.container} colors={gradients.teal}>
<ScrollView contentContainerStyle={styles.scrollView}>
{loading && (
<View style={styles.loadingContainer}>
<Loading />
</View>
)}
<MountainHero text='Explore' />
<Typeahead
style={styles.typeahead}
placeholder='Search Cities'
value={props.exploreSearch}
onChange={props.setExploreSearch}
vals={props.exploreTypeahead}
valKey={'place_id'}
onTypeaheadClick={props.onExploreTypeaheadClick}
/>
<CardRow
text='Explore Places'
cards={recommended}
type='location' />
<CardRow
text='In the Spotlight'
cards={spotlight}
type='location' />
</ScrollView>
</LinearGradient>
)
}
const mapStateToProps = state => ({
authenticated: state.users.authenticated,
spotlight: state.locations.spotlight,
exploreSearch: state.locations.exploreSearch,
exploreTypeahead: state.locations.exploreTypeahead,
loading: state.locations.loading,
})
const mapDispatchToProps = dispatch => ({
setExploreSearch: s => dispatch(setExploreSearch(s)),
onExploreTypeaheadClick: val => dispatch(onExploreTypeaheadClick(val)),
})
export default connect(mapStateToProps, mapDispatchToProps)(Explore)
Typeahead.js
import React from 'react'
import { Text, View, TouchableOpacity } from 'react-native'
import { sizing, GradientInput } from '../style'
const styles = {
container: {
position: 'absolute',
zIndex: 100,
elevation: 100,
height: 400,
width: '100%',
},
input: {
width: '100%',
borderRadius: 0,
},
typeaheadContainer: {
position: 'absolute',
zIndex: 100,
elevation: 100,
top: 55,
width: '100%',
},
typeaheadRow: {
padding: 10,
paddingTop: 12,
paddingBottom: 12,
borderWidth: 1,
borderColor: '#eeeeee',
backgroundColor: '#ffffff',
marginBottom: -1,
},
typeaheadRowText: {
fontSize: 15,
fontFamily: 'open-sans',
lineHeight: 20,
backgroundColor: '#ffffff',
},
}
export const Typeahead = props => {
return (
<View style={[props.container, props.style]}>
<GradientInput style={styles.input}
placeholder={props.placeholder}
value={props.value}
onChange={props.onChange} />
<TypeaheadList vals={props.vals}
valKey={props.valKey}
onTypeaheadClick={props.onTypeaheadClick} />
</View>
)
}
export const TypeaheadList = props => {
if (!props.vals) return null;
return (
<View style={styles.typeaheadContainer}>
{props.vals.map(i => {
let text = i.text;
if (text.length > 31) text = text.substring(0,31) + '...';
return (
<TouchableOpacity activeOpacity={0.5} key={i[props.valKey]}
style={styles.typeaheadRow}
onPress={() => props.onTypeaheadClick(i[props.valKey])}>
<Text numberOfLines={1} style={styles.typeaheadRowText}>{text}</Text>
</TouchableOpacity>
)
})}
</View>
)
}
export default Typeahead