I made a search input on the top of a map view to look in the data. When the flatlist shows up I have two problems that I don’t understand:
- I can’t scroll in the list to search into it.
- And when I do that, it moves the map behind.
The TouchableOpacity
of the item in the list works. So it’s like I can touch both views.
Here is the code:
import { StyleSheet, Text, TextInput, View, TouchableHighlight, Pressable, TouchableOpacity, FlatList } from 'react-native'
// import { FlatList } from 'react-native-gesture-handler'
import React, { useState} from 'react'
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
import { useGetAllBars } from '../../hooks/queries-hook';
import Loader from '../../components/ui/loader';
const Search = () => {
const { getbars, isLoading, data, error } = useGetAllBars();
const [showList, setShowList] = useState(false)
const [text, setText] = useState("")
const [list, setList] = useState(null)
const handleSearch = (text) => {
if (text) {
let filteredList = data.filter((item) =>
item.name.toLowerCase().includes(text.toLowerCase()))
setList(filteredList)
}
}
const renderItem = ({ item }) => {
return (
<TouchableOpacity onPress={() => { }} >
<View style={styles.item}>
<Text style={styles.simpleText}>{item.name}</Text>
</View>
</TouchableOpacity>
);
};
return (
<View style={styles.searchView}>
{
text.length > 2 && showList ?
<View style={styles.listView}>
{
isLoading ? <Loader fullScreen={false} /> :
<View style={{ height: 320 }}>
<FlatList
data={list.slice(0, 50)}
renderItem={renderItem}
keyExtractor={item => item.id}
/>
</View>
}
</View>
:
text != "" &&
<View style={styles.listView}>
<Text style={styles.alert}>Minimum 3 caractères</Text>
</View>
}
<View style={styles.searchInput}>
<MaterialCommunityIcons name="magnify" size={20} color={'#000'} />
<TextInput style={styles.textToSearch}
placeholder='Search for a place'
placeholderTextColor={"#777777"}
onFocus={() => {
!data && getbars()
setShowList(true)
}}
onChangeText={(text) => {
setText(text);
handleSearch(text);
}}
value={text}
/>
{
text != "" &&
<TouchableOpacity
onPress={() => { setText("") }} >
<MaterialCommunityIcons name="close-circle" size={30} color={'#777'} />
</TouchableOpacity>
}
</View>
</View>
)
}
export default Search
const styles = StyleSheet.create({
searchView: {
margin: 5,
width: "95%",
position: 'absolute',
zIndex: 10,
bottom: 0,
},
listView: {
margin: 5,
marginVertical: 20,
width: "100%",
position: 'absolute',
bottom: 40,
backgroundColor: "#fff",
borderRadius: 10,
minHeight: 30,
shadowColor: "#000",
shadowOffset: {
width: 0,
height: 2
},
shadowOpacity: 0.25,
shadowRadius: 4,
elevation: 5
},
searchInput: {
paddingHorizontal: 10,
lineHeight: 20,
flexDirection: 'row',
width: "80%",
backgroundColor: '#d9dbda',
borderRadius: 10,
alignItems: 'center',
height: 50,
},
textToSearch: {
fontSize: 20,
color: "#777777",
width: "85%",
paddingHorizontal: 5,
paddingVertical: 0,
},
simpleText: {
color: "#777777"
},
alert: {
color: "#634a",
lineHeight: 30,
flexDirection: 'row',
alignItems: 'center',
margin: 3
},
item: {
flexDirection: "row",
justifyContent: 'flex-start',
margin: 2
},
})
Could someone explain me what I am missing or what I dont understand ?
2
Answers
I think the problem is that the parent of the absolute positioned list is collapsed and make the list become an overflowed content. React native has a wired behavior that touching interaction on overflowed content is workable but guesture moveing is not. That’s why your gesture moving event will be responded by the map behind as it is the only responder.
Try import FlatList from react-native-gesture-handler instead of using the react-native one. And you may need to set the responder of your gesture event when the list shows.
import { FlatList } from 'react-native-gesture-handler'
.Or just set the parent height when the list shows to ensure the list will not be overflowed
Would need to see the parent structure of how the map is being render alongside search.
This could be a layering issue on android. Android specifically needs to have elements that appear on top return a line lower than the jsx elements that and rendered below.
Without this structure you have to use elevation (but that may not work with a OpenGL map layer).
Noting that opengl layers can behave differently than simple react native views, especially on android.
If this is not on android, look at zindex for ios. Ios should be more flexible with view hierarchy.