Touchablehighlight not clickable if position absolute - react-native

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>

Related

When stickyHeaderIndices is used, style of component changes

I've searched common problems and how to use stickyHeaderIndices and so on. But stuck with one point, and I didn't even find why this occurs, so couldn't search on the internet.
Everything works fine on web, but not on my phone when I use sticky.
My Scroll View Structure:
<ScrollView stickyHeaderIndices={[0]} style={styles.layout}>
<View style={styles.topBar}>
<Text style={styles.title}>Messages</Text>
<View style={styles.notificationIcon}>
<Text style={styles.notificationIconTxt}>{notificationCount}</Text>
</View>
</View>
<ChatItem pairingCategory={'Name'} />
</ScrollView>
View that I want to stick on top:
If I use the structure above, it sticks on top but style of the component changes (as in the picture below), I want that bubble to stay next to text.
Here's my styles:
const styles = StyleSheet.create({
layout: {
flex: 1,
backgroundColor: colors.lightBg
},
topBar: {
backgroundColor: colors.lightBg,
paddingVertical: 15,
paddingLeft: 24,
flexDirection: 'row',
flexWrap: 'nowrap',
alignItems: 'center',
},
title: {
fontSize: 32,
marginRight: 8,
},
notificationIcon: {
borderRadius: 15,
justifyContent: 'center',
alignItems: 'center',
width: 30,
height: 30,
backgroundColor: colors.mainBg,
padding: 5
},
notificationIconTxt: {
color: 'white',
fontWeight: "700"
}
})
Whenever I delete stickyHeaderIndices, topBar view seems the way I want, but not sticks to top.
Why it happens, and what can I do to solve it?
Solved!
I still don't know, what was the reason for it, but created new component called ChatListTopBar then wrapped my first children View.
function ChatListTopBar({notificationCount}) {
return (
<View style={styles.topBar}>
<Text lineBreakMode='false' style={styles.title}>Mesajlar</Text>
<View style={styles.notificationIcon}>
<Text style={styles.notificationIconTxt}>15</Text>
</View>
</View>
)
}
//ScrollView section seems so
<ScrollView stickyHeaderIndices={[0]} style={styles.layout}>
<ChatListTopBar notificationCount={notificationCount} />
<ChatItem pairingCategory={'Name'} />
</ScrollView>
Replacing like so, just fixed the issue!
wrap your View which you are trying to stick with <></>

React Native TouchableWithoutFeedback on view with position absolute

I have a modal that I want show when the user clicks a i button.
The modal envelops the entire screen, by setting the position to 'absolute'. This works fine, but when the user clicks somewhere on the screen, it should disappear again.
My TouchAbleWithoutFeedback however, does not register a press. It appears to be having something to do with the position being absolute but I can't put my finger on it.
Also, the clickable elements underneath the modal are still interactable, even though the modal is displayed on top of those elements.
Here is my code:
import { TouchableWithoutFeedback } from 'react-native-gesture-handler';
render()
{
return (<View>
<View style={styles.container}>
<OtherElements/>
</View>
<MainScreenInfoModal showModal={this.state.showInfoModal} />
</View>);
}
const MainScreenInfoModal = ({showModal}) =>
{
if (showModal)
{
return <TouchableWithoutFeedback style={{zIndex: 10}} width={window.width} height={window.height} onPress={() => {console.log('press!')}}>
<View style={styles.infoModal} >
<SvgXml width={300} height={300} xml={mainscreenInfomodal} style={{
alignSelf: 'center',
marginTop: window.height * .45
}}/>
</View>
</TouchableWithoutFeedback>
}
return null;
}
const styles = StyleSheet.create({
container:
{
fontSize: 26,
textAlign: 'center',
display: 'flex',
flexDirection: 'column',
justifyContent: 'flex-start',
alignItems: 'center',
padding: 13,
fontWeight: "bold",
},
{...} ,
infoModal:
{
position: 'absolute',
bottom: 0,
width: window.width,
height: window.height,
backgroundColor: 'rgba(255,255,255,0.7)',
zIndex: 10
}});
try react-native-modalize library, it saved me alot of time and nerves developing modals

How to achieve drop-shadow with no blur in React Native

I'm new using React Native and I'm trying to map the following component (made in web) but for React Native with no success:
Elevation and shadow properties does not do the trick because they add some blur to the resulting shadow. Which would be the proper way to handle this?
Regards
Use react-native-cardview
import React, { Component } from 'react';
import {
View,
ScrollView,
TextInput,
} from 'react-native';
import CardView from 'react-native-cardview';
import styles from './styles';
export default class Signup extends Component {
render() {
return (
<View style={{ flex: 1, backgroundColor: colors.whiteColor }}>
<ScrollView contentContainerStyle={styles.signupContainer}>
<View style={styles.signupInputs}>
<CardView
style={styles.cardStyle}
cardElevation={2}
cardMaxElevation={2}
cornerRadius={5}
>
<TextInput
underlineColorAndroid="transparent"
style={[styles.signupInput, styles.commonsignupStyle]}
placeholder="Nom *"
placeholderTextColor={colors.primaryColor}
/>
</CardView>
<CardView
style={styles.cardStyle}
cardElevation={2}
cardMaxElevation={2}
cornerRadius={5}
>
<TextInput
underlineColorAndroid="transparent"
style={[styles.signupInput, styles.commonsignupStyle]}
placeholder="Prénom *"
placeholderTextColor={colors.primaryColor}
/>
</CardView>
</View>
</ScrollView>
</View>
);
}
}
Edit:
For dynamic height, two lines or more of text, as asked for in the comments, I had to use another workaround.
https://snack.expo.io/7bVXvbmE0
const Label = () => {
return <View style={{width: 100, height: 50}}>
<View style={styles.topView}>
<Text>Hello world</Text>
<Text>Hi world</Text>
</View>
<View style={styles.shadowView} >
<Text style={{color: 'transparent'}}>Hello world</Text>
<Text style={{color: 'transparent'}}>Hi world</Text>
</View>
</View>;
}
Whatever dynamic text you have on the label, duplicate for the shadow label, but make it transparent. That way you are guaranteed that the shadow follows the top view.
Also, get rid of the hardcoded heights in the styles. For both top view and shadow view, their heights are informed by the text input, and the wrapper container's height is informed by the two views.
Lastly, change shadow view style's top to be just a few points above 0 to make sure you it peeks from under topview. You can adjust borderRadius of the shadow view to fit your preferences.
const styles = StyleSheet.create({
topView: {
width: '100%',
position: 'absolute',
top: 0, backgroundColor: 'white',
justifyContent: 'center',
alignItems: 'center',
borderRadius: 25,
},
shadowView: {
position: 'absolute',
top: 3,
width: '100%',
zIndex: -10,
borderRadius: 17,
backgroundColor: '#ddd'}
});
Previous Post
A little bit hacky, but you can do this if you absolutely don't want any blur.
https://snack.expo.io/pWyPplcm3
const Label = () => {
return <View style={{width: 100, height: 30}}>
<View style={styles.topView}>
<Text>Hello world</Text>
</View>
<View style={styles.shadowView} />
</View>;
}
styles:
const styles = StyleSheet.create({
topView: {
height: 25,
width: '100%',
position: 'absolute',
top: 0, backgroundColor: 'white',
justifyContent: 'center',
alignItems: 'center',
borderRadius: 15,
},
shadowView: {
position: 'absolute',
top: 0,
height: 28,
width: '100%',
zIndex: -10,
borderRadius: 13,
backgroundColor: '#ddd'}
});

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

react-native style opacity for parent and child

react-native : I have one View and the child of View is an Image , I applied opacity: 0.5 for View and opacity: 0.9 for an Image but it doesn't apply for Image ,the parent opacity is applying for child , the child doesn't take independent opacity
Try changing the opacity using alpha-value of the background color instead. Then it should be possible applying different opacities for children.
For example:
<View style={{backgroundColor: 'rgba(0,0,0,0.5)'}}/>
React-Native 0.60+
There is a new opacity prop that you can pass in:
<View style={{opacity: 0.5}} />
React-Native 0.59.x and lower
Like this (with 50% at the end of color hash):
<View style={{backgroundColor: '#FFFFFF50'}} />
Or RGBa way:
<View style={{backgroundColor: 'rgba(0,0,0,0.5)'}} />
In react-native 0.6, you can use the opacity prop on a View. Example:
<View opacity={1.0} />
<View opacity={0.5} />
1.0 = opaque (alpha == 1.0)
0.0 = clear (alpha == 0.0)
See https://facebook.github.io/react-native/docs/0.6/view-style-props#opacity
Snack: https://snack.expo.io/S1KjXqe6N
If you want to display some text with transparent alpha opacity then I have the best way, just try.
TransparentBG:{
backgroundColor: '#00000070',
color:'#FFFFFF'
}
here, "70" indicates opacity %.
-Thanks
You need to use needsOffscreenAlphaCompositing like this-
<View needsOffscreenAlphaCompositing>
...
<View/>
If you want to change the opacity of a view that doesn't recognize the opacity prop (such as a TouchableOpacity), wrap it in a View first and change the opacity prop of that.
<View opacity={0.3}>
<TouchableOpacity>
</TouchableOpacity>
</View>
You can't change parent opacity without affecting child, so you should have absolute positioned background. For proper child positioning, you should add an additional container. Check out this snack: snack.expo.io/SkaHLjzr8
...
<View style={styles.container}>
<View style={styles.card} >
<View style={styles.background} />
<View style={styles.imageContainer}>
<Image style={styles.image} source="..." />
</View>
</View>
</View>
...
...
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
},
background: {
...StyleSheet.absoluteFillObject,
backgroundColor: 'blue',
opacity: .5,
zIndex: 1,
},
card: {
height: 400,
},
imageContainer: {
...StyleSheet.absoluteFillObject,
justifyContent: 'center',
alignItems: 'center',
zIndex: 2,
opacity: 0.8,
},
image: {
width: 200,
height: 200
}
...
HACK FOR BACKGROUNDS OPACITY
Use combination of 2 backgroundColor in order to imitate the opacity
After playing sometimes and be lost on the internet to find a simple solucion, I realized that at the current React-Native Version V 0.64 the opacity for the backgrounds, at least as it is commonly used for Web Dev just is not suited for React-Native.
APP
Use ImageBackground Component --> DOCS:
Set you background image on the ImageBackground
import React from 'react';
import { ImageBackground, View, Text, StyleSheet, ScrollView} from 'react-native';
const App = () => {
return (
<ImageBackground style={ mainStyle.background } source={ { uri: "https://reactjs.org/logo-og.png" } } resizeMode="cover">
<ScrollView style={ mainStyle.overlay }> // Here its style will be used as opacity
<View style={ mainStyle.containerCenter}>
<View style={ mainStyle.homeTitleWraper}>
<Text style={ mainStyle.homeTitle }> Hello WOrld</Text>
</View>
</View>
</ScrollView>
</ImageBackground>
);};
export default App;
Style
Style, Here the First Child of the Background has to take the whole
screen size, with style overlay it will lay down like a thin blanket on top of the Background, imitating the opacity.
const mainStyle = StyleSheet.create({
background: {
width: "100%",
height: "100%",
},
overlay: {
backgroundColor: 'rgba(255, 255, 255, .5)' // HERE USE THE LAST DIGIT AS IF IT WERE OPACITY
},
containerCenter : {
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
paddingHorizontal: 30,
marginVertical: 60,
},
homeTitleWraper: {
paddingHorizontal: 40,
paddingVertical: 100,
},
homeTitle: {
fontSize: 40,
fontWeight: "900",
textAlign: "center",
textTransform: "uppercase",
color: "white",
fontStyle: "italic",
},
containerSmall: {
marginVertical: 10,
width: "100%"
}