How to style a component to hide behind another component - react-native

I'm quite new to react native, I'm trying to understand how I can style two components to intercept with each other. Desirably have one component move behind the other component as if they were layers in Photoshop. I'd like to achieve this so that I can animate the styling of the hidden component to reveal it self on press of a touchable opacity. But i'm fine with the animation, I don't need any help there. I only need direction with how to correctly style a component to hide behind another component.
Here are the two components I'm working with, a text component contained inside a touchable opacity (the text box), and a date of publish text component. Both of which are contained inside a main view component.
<View style={styles.contentContainer}>
<View style={styles.dateContainer}>
<Text style={styles.dateText}>a few seconds ago</Text>
</View>
<TouchableOpacity onPress={() => {}}>
<Text style={styles.item}>this is some text input</Text>
</TouchableOpacity>
</View>
const styles = StyleSheet.create({
contentContainer: {
flex: 1,
},
item: {
padding: 16,
fontWeight: 'bold',
borderColor: '#bbb',
borderWidth: 1,
borderStyle: 'solid',
borderRadius: 10,
},
dateContainer: {
flex: 1,
paddingHorizontal: 2,
marginTop: 16,
alignSelf: 'flex-end',
},
dateText: {
color: '#adadad',
},
});

You can use the position:'absolute' and the zIndex in styles to have the layers for views.
The below style would place the dateContainer above the text component and in the corner of the text compoment. You can position the view using left,right,top or bottom.
dateContainer: {
position: 'absolute',
flex: 1,
paddingHorizontal: 2,
top: 30,
alignSelf: 'flex-end',
zIndex: 1000,
},

Related

Touchable Opacity in FlatList doesn't respond to touch

I am displaying the state array below using the FlatList provided. However, the TouchableOpacity elements in Key exhibit no response whatsoever to a press. The issue persists even if I change the TO to a button or a pressable. Does anyone have a solution for this issue because it has never happened before even when using very similar code.
const [keyboard, setKeyboard] = useState([
{char: 'a', background: 'white', border: 'black', text: 'black'},
.
.
.
{char: 'z', background: 'white', border: 'black', text: 'black'},
]);
const Key = ({letter, background, border, textColor}) => {
return(
<TouchableOpacity style = {[styles.key, {backgroundColor: {background}}, {borderColor: {border}}]} onPress = {() => console.log({letter})}>
<Text style = {[styles.letter, {color: {textColor}}]}>{letter}</Text>
</TouchableOpacity>
);
};
<FlatList
contentContainerStyle = {styles.keyboard}
data={keyboard}
renderItem= {({item}) => <Key letter={item.char} background={item.background} border={item.border} textColor={item.text}/>}
keyExtractor={(item) => item.char}
numColumns = {6}
/>
Styles:
keyboard:{
width: '100%',
height: '40%',
alignItems: 'center',
justifyContent: 'center',
position: 'absolute',
transform:[{translateY: 420}],
flex: 1,
},
letter:{
fontSize: 25,
fontWeight: 'bold',
position: 'absolute',
},
key:{
height: 50,
width: 60,
borderWidth: 3,
borderRadius: 10,
alignItems: 'center',
justifyContent: 'center',
},
the code is working fine ,
the issue with styling is your are passing its as object
{background:{background}} instead this use {background:background}
here is the link of expo I tested
see here its working with styling and also touchable
hope its help you
The issue with this code is that I had a Modal open. TouchableOpacity components seem to not respond to touch when a Modal is open. Instead use a conditionally rendered view.
{ {CONDITION HERE} ?(
{WHAT WILL BE RENDERED IF CONDITION IS SATISFIED HERE}
): {WHAT WILL BE RENDERED IF CONDITION IS NOT SATISFIED HERE; null or some other component}}

React Native Maps with sticky and multiple Callouts - Same as Uber app

I would like to have multiple callout which are alway open in the same way as Uber taxi app does.
The criteria I want are
Multiple Callouts
Callout can be pressed
I have two solutions. One is to always set callouts open by reference once it is mounted, but it comes with only one active callout at once. Secondly, I use custom Marker with absolute position and TouchableOpacity as child. I can display multiple, but the button nested in <MapView.Marker> cannot be pressed.
I was struggling with the same problem for sometime. Actually this is how I stumbled across this question. I wanted to share what I ended up with. Apparently we can place anything inside the Marker component, so putting a View and an Image inside did the trick:
<Marker coordinate={coords} style={styl.customMarker}>
<View style={styl.addressBox}>
<TouchableOpacity onPress={() => console.log('Click!')}>
<Text numberOfLines={2} style={styl.addressText}>
Some location address goes here
</Text>
</TouchableOpacity>
</View>
<Image source={require('../assets/locationPin.png')} />
</Marker>
const styl = StyleSheet.create({
customMarker: {
justifyContent: 'center',
alignItems: 'center'
},
addressBox: {
width: 150,
height: 45,
backgroundColor: '#fff',
paddingVertical: 5,
paddingHorizontal: 7,
borderRadius: 5,
borderWidth: 0.5,
borderColor: '#ccc',
shadowColor: '#000',
shadowOffset: { width: 0, height: 1 },
shadowOpacity: 0.3,
shadowRadius: 5,
elevation: 3
},
addressText: {
textDecorationLine: 'underline'
}
});
This is how it looks:
This is a Grab (Uber alternative) implementation. But you can play around with View and Image styles to achieve Uber like results.
Hope this helps someone in the future. Cheers!

How to position a button in bottom right corner of MapView in React Native?

I'm trying to wrap my head around flexbox, and also how the component tree works with a react-native-maps MapView (and whether that's different from other components with components "on top of them" for which I'm currently using Callout.
For example, here's my MapView's render method. The TouchableOpacity area (and its buttonCallout container. is currently just for my experiments in understanding layout. I'm using the F8StyleSheet wrapper from makeitopen.com
render() {
return (
<View style={styles.container}>
<MapView
style={{ flex: 1 }}
region={this.state.region}
showsUserLocation={true}
>
{this.renderMarkers()}
</MapView>
<Callout style={styles.searchCallout}>
<TextInput
onChangeText={searchText => this.setState({ searchText })}
onSubmitEditing={this.handleSearch.bind(this)}
style={styles.calloutSearch}
placeholder={"Search"}
value={this.state.searchText}
/>
</Callout>
<Callout style={styles.buttonCallout}>
<TouchableOpacity
style={[styles.touchable]}
onPress={() => console.log("press")}
>
<Text style={styles.touchableText}>Press Me 1</Text>
</TouchableOpacity>
<TouchableOpacity
style={[styles.touchable]}
onPress={() => console.log("press")}
>
<Text style={styles.touchableText}>Press Me 2</Text>
</TouchableOpacity>
</Callout>
</View>
);
}
}
const styles = F8StyleSheet.create({
container: {
flex: 1
},
buttonCallout: {
flex: 1,
alignSelf: "flex-end",
justifyContent: "space-between",
backgroundColor: "transparent",
borderWidth: 0.5,
ios: { padding: 5 },
borderRadius: 20
},
touchable: {
backgroundColor: "lightblue",
padding: 10,
margin: 10
},
touchableText: {
fontSize: 24
},
searchCallout: {
flexDirection: "row",
backgroundColor: "rgba(255, 255, 255, 0.9)",
borderRadius: 10,
width: "80%",
marginLeft: "5%",
marginTop: 40
},
calloutSearch: {
borderColor: "transparent",
marginLeft: 10,
width: "90%",
marginRight: 10,
height: 40,
borderWidth: 0.0
}
});
It makes sense how I use margins to get the searchCallout to be where I want it to be because it's at the top.
As the code is now, the buttonCallout (with the TouchableOpacity inside) renders in the top right corner (sensible - alignSelf: 'flex-end' puts it at the "end", on the right).
...
Mid-post update! By changing the styles.container's flexDirection to row, with the buttons callout at alignSelf: flex-end. I've got the button callout on the bottom, and the search callout is still on top. I guess Callout components all render on top of each other.
So now I can use justifyContent on styles.container to have both callouts either in the center or on the left or right (center, flex-start, flex-end). How do I justify the different items separately? (justifySelf is not a thing!)
Wrapping both callouts in a unstyled View component results in the button callout rendering at the top-right but the search callout being nowhere to be found.
Wrapping them both in a callout results in the buttons rendering a little right of the top left corner, with the search callout again not displayed.
Help me understand all this! Thanks :)
if you're trying to position the buttonCallout at the bottom, give it a postion:'absolute', so it will stay at the bottom
buttonCallout: {
flex: 1,
flexDirection:'row',
position:'absolute',
bottom:10,
alignSelf: "center",
justifyContent: "space-between",
backgroundColor: "transparent",
borderWidth: 0.5,
borderRadius: 20
},

TouchOpacity does not cover whole menu link

I just started using react-native so sorry if it's a trivial question.
I'm trying to create a sidebar with multiple links in it. The sidebar works fine but the issue is with the links themselves. Below is the jsx for the link.
<TouchableOpacity style={MenuItemStyles.ItemWrapper} onPress={this.props.onPress}>
<View style={MenuItemStyles.itemIcon}>
<Icon
name={this.props.iconName}
size={this.props.size || 30}
color={Colours.LightGrey}
/>
</View>
<Text style={MenuItemStyles.itemLabel}>
{this.props.label}
</Text>
</TouchableOpacity>
And the style:
const MenuItemStyles = StyleSheet.create({
ItemWrapper: {
flexDirection: 'row',
alignSelf: 'stretch',
marginTop: 10,
width: 100,
marginBottom: 10
},
itemIcon: {
alignItems: 'center',
alignSelf: 'center',
width: 80,
},
itemLabel: {
color: '#000000',
fontSize: 20,
fontFamily: 'sans-serif-light',
textAlign: 'center',
marginLeft: 5,
}
});
The link contains an icon(Material style), follows by the label. The onPress event is registered correctly. However the click area size is very small ie onPress only triggers when pressing on the icon, not the label. I would assume TouchableOpacity covers all nested component?Can I control how wide TouchableOpacity cover?
Thanks
Wrap your <TouchableOpacity/>component in view that has the style you are curenttly assigning on TouchableOpacity like this <View style={MenuItemStyles.ItemWrapper}>
and by adding flex:1 on the <TouchableOpacity/> component it will inherit the size of the <View>
heres a working example of what I think you are trying to accomplish with the solution above implemented:
https://rnplay.org/apps/SW983Q

Touchablehighlight not clickable if position absolute

I have a Touchablehighlight that I need to position absolute, but it becomes unclickable after I do it.
What could cause this? It functions like it should if I dont have the position set to absolute.
Solution was to change the order of the components.
What i originally had:
<TouchableHighLight><Text>Click me</Text></TouchableHighlight>
<View> .... </View>
This was the fix:
<View>...</View>
<TouchableHighLight><Text>Click me</Text></TouchableHighlight>
Dude just go and add zIndex : 1 to the view containing the buttons and boom you are done in most of the cases. Also note adding elevation adds shadow to android button and sometimes elevation may also be a issue if its added to parent and not added to child then the child button may not work.(Rare Case)
eg:
buttonContainers:
{
zIndex: 1,
alignSelf: 'flex-end',
position: 'absolute',
top:5,
right: 5,
height: 40,
borderWidth: 1,
justifyContent: 'center',
alignContent: 'center',
width: 80
},
SOLVED:
I faced this issue today. I have solved it.
Import TouchableOpacity from react-native-gesture-handler instead of react-native.
Before:
import {TouchableOpacity} from "react-native";
After:
import {TouchableOpacity} from 'react-native-gesture-handler'
use onPressIn instead of onPress
That made the area clickable!
I used TouchableOpacity inside an absolute view. The onPress function was not called after press it. But the opacity changed. I've tried all the above solutions, but none works.
My solutions is use onPressIn instead of onPress.
It seems like the inner action of Touchable* is weird in ReactNative when it's in an absolute view.
After trying everything for two hours, the solution I found was to change my button position.
Before ...
export default class Navbar extends Component {
componentDidMount() {
console.log(this.props);
}
render() {
return (
<View style={styles.content}>
<TouchableOpacity
onPress={this.props.openModal}
style={styles.containerButton}
>
<Text>New</Text>
</TouchableOpacity>
<Text style={styles.textCenter}>Remember me</Text>
</View>
);
}
}
const styles = StyleSheet.create({
content: {
paddingTop: 30,
paddingBottom: 10,
backgroundColor: '#81C04D',
flexDirection: 'row'
},
containerButton: {
position: 'absolute',
top: 30,
left: 8
},
textCenter: {
flex: 1,
textAlign: 'center',
fontWeight: 'bold'
}
});
After ...
export default class Navbar extends Component {
componentDidMount() {
console.log(this.props);
}
render() {
return (
<View style={styles.content}>
<Text style={styles.textCenter}>Remember me</Text>
<TouchableOpacity
onPress={this.props.openModal}
style={styles.containerButton}
>
<Text>New</Text>
</TouchableOpacity>
</View>
);
}
}
const styles = StyleSheet.create({
content: {
paddingTop: 30,
paddingBottom: 10,
backgroundColor: '#81C04D',
flexDirection: 'row'
},
containerButton: {
position: 'absolute',
top: 30,
left: 8
},
textCenter: {
flex: 1,
textAlign: 'center',
fontWeight: 'bold'
}
});
It works!!!
My solutions is:
style:{
zIndex: 1,
position: 'absolute',
}
use
zIndex: 1 in view, it'll work.
<View style={{position : 'absolute', marginTop : 25, zIndex: 1}}>
More details can be found here :
How to use zIndex in react-native
For me, it works like:
import { TouchableOpacity } from 'react-native';
onPress, zIndex: 1, position: 'absolute'
One more solution.....
For me what worked was a combination of things....
import { TouchableOpacity } from 'react-native-gesture-handler'
and I WRAPPED my TouchableOpacity in a View.
before:
<TouchableOpacity onPress={()=> addCallback()}
style={styles.addButtonHolder}
>
<PlusCircle style={styles.addButton} width={70} height={70} stroke={"white"} strokeWidth={3}/>
</TouchableOpacity>
after:
<View style={styles.addButtonHolder}>
<TouchableOpacity onPress={()=> addCallback()}>
<PlusCircle style={styles.addButton} width={70} height={70} stroke={"white"} strokeWidth={3}/>
</TouchableOpacity>
</View>
StyleSheet:
const styles = StyleSheet.create({
addButtonHolder: {
position: 'absolute',
bottom: 70,
right: 10,
justifyContent: 'center',
alignItems: 'center',
zIndex: 1,
},
addButton: {
backgroundColor: '#b4cffa',
borderRadius: 35
}
})
This worked for me
import { TouchableOpacity } from 'react-native-gesture-handler'
and changed onPress to onPressIn
<TouchableOpacity onPressIn={() => console.log('clicked')}></TouchableOpacity>
My solution was to import TouchableHighlight from 'react-native'
It was originally imported from 'react-native-gesture-handler'
This props help to disable ScrollView to catch all touches and let child handles
keyboardShouldPersistTaps='always'
'always', the keyboard will not dismiss automatically, and the scroll view will not catch taps, but children of the scroll view can catch taps.
'handled', the keyboard will not dismiss automatically when the tap was handled by children of the scroll view (or captured by an ancestor).
https://reactnative.dev/docs/scrollview#keyboardshouldpersisttaps
When the position is absolute, TouchableHighlight or TouchableOpacity goes beneath from the surface. You have to add a higher zIndex value to the Container.
He guy, I took a long time to find out why this happens.
I tested a lot of the solution here. Two things worked for:
The first answer here
The second one is to add elevation and zIndex on the wrapper container
<View style={{ zIndex:0 }>
...
<View style={{ position: 'absulote', zIndex:10 ,elevation: 10 }}>
<TouchableHighLight><Text>Click me</Text></TouchableHighlight>
</View>
<View> .... </View>
...
</View>
If I am right, the reason for that is even that the button is shown, Android treats differently the layers of the Press events and you need to set a low level for the rest of your components. Defining a lower level for your wrapper component, all its children without this attribute will automatically inherit from the parent.
My problem was quite different, a backgroundColor style property was set on the container of my button. The color didn't work. I missed to remove this useless property. Finally, this backgroundColor was making an invisible sheet above my button. Removing it make it clickable again.
I faced the problem only on Android.
Add a zIndex to the component where you added position absolute. This solved the issue for me.
position: 'absolute',
zIndex: 1,
`
I ran into a similar problem, what I did was, I enclosed the whole thing into a new View and instead of giving 'absolute' position to
the TouchableOpacity, I gave it to the parent View. That made the
Opacity again clickable somehow. Here is the code snippet of before
and after
My Code before
<TouchableOpacity
onPress={() => {
console.log("hah");
}}
style={{
height: 50, width: 50,
backgroundColor: 'rgb(90,135,235)',
borderRadius: 25, alignItems: 'center',
justifyContent: 'center', right: 0,position:'absolute'
}}>
<Image source={require('../assets/images/element-acorn-white.webp')}
style={{ height: 30, width: 30, resizeMode: 'contain' }} />
</TouchableOpacity>
After Wrapping into a View with 'absolute'
<View style={{
alignItems: 'flex-end', position: 'absolute',
bottom: Dimensions.get('screen').height / 5
}}>
<TouchableOpacity
onPress={() => {
console.log("hah");
}}
style={{
height: 50, width: 50,
backgroundColor: 'rgb(90,135,235)',
borderRadius: 25, alignItems: 'center',
justifyContent: 'center', right: 0,
}}>
<Image source={require('../assets/images/element-acorn-white.webp')}
style={{ height: 30, width: 30, resizeMode: 'contain' }} />
</TouchableOpacity>
</View>