React-native: transparent view over ScrollView - react-native

I'm having problems setting transparency for a View that is outside of the ScrollView. I'm using Expo. The idea is that when you scroll the long scrollview content, you should just about to see it behind the bottom view. I've tried the opacity property as well as setting the background color using rgba(x,x,x, 0.5) with no luck. It looks like anything outside the Scrollview is totally opaque in relation to the scrollview content behind it.
Basic Code (the link to the snack is below):
export default function App() {
return (
<View style={styles.container}>
<ScrollView>
<View style={styles.transparentWrapper}>
<Text style={styles.textElement}>This is some text wrapped in a transparent View</Text>
</View>
<Text style={styles.paragraph}>
Lorem....
</Text>
<Text style={styles.paragraph}>
Lorem ...
</Text>
</ScrollView>
<View style={styles.bottomPart}>
<Text style={styles.textElement}>This is some text. Its wrapping view is transparent but I cannot see the lorem text underneath it.</Text>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
},
paragraph: {
fontSize: 30,
marginBottom: 15,
},
textElement: {
color: 'blue',
},
transparentWrapper: {
position: 'absolute',
height: 100,
justifyContent: 'center',
top: 450,
left: 50,
backgroundColor: 'transparent',
zIndex: 999,
},
bottomPart: {
height: 50,
backgroundColor: 'transparent',
}
});
Full snack is here:
https://snack.expo.dev/#wastelandtime/scrollview-transparency
Here's an expected outcome. The top blue text is wrapped in a transparent view (and this is what it's supposed to look like) it's not a problem as it's within the ScrollView.
The bottom blue text does not seem to honour any transparency in terms of the scroll content behind it (I'd like just to see the blue text with complete transparency on the wrapping View.

it can be achieved without position: 'absolute', with negative margin in this way,
bottomPart: {
height: 50,
backgroundColor: 'transparent',
marginTop: -50, // add this
}
using negative top margin the text can be pushed upwards
snack link here https://snack.expo.dev/CJBbhSCzg

Setting bottomPart position to absolute and bottom: 0
bottomPart: {
height: 50,
backgroundColor: 'transparent',
position: 'absolute',
bottom: 0
}
You should get something like this.
You may also want to add marginBottom: 50, to the last element inside the ScrollView if you'll put a solid element inside the bottom part.

Related

How do you vertically and horizontally center a View with respect to another View that is at a higher zIndex (React Native)?

Image of what I am envisioning
I'm trying to add a center tick mark to a slider.
Is it possible to vertically and horizontally center View 1 with respect to View 2 and at the same time render View 2 above View 1 (using zIndex)? I can accomplish this by placing View 1 below View 2 in the Y direction and set the margin of View 1 so it appears underneath View 2 (in the Z direction). Is that the correct way to do this?
Accomplishing this by fiddling with the margins seems like it could cause problems on different size screens.
Try giving view1 and view2 absolute positions, and place them in a parent container that centers vertically and horizontally. This will allow them to overlap without having to play with margin, and will naturally place the view2 on top of view1 without having to use zIndex
export default function App() {
return (
<View style={styles.container}>
<View style={styles.specialContainer}>
<View style={styles.tall}/>
<View style={styles.long}/>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#ecf0f1',
padding: 8,
},
specialContainer:{
width:300,
aspectRatio:1,
backgroundColor:'pink',
alignItems:'center',
justifyContent:'center'
},
long:{
position:'absolute',
backgroundColor:'purple',
width:'60%',
height:24,
// alignSelf:'center'
},
tall:{
position:'absolute',
backgroundColor:'green',
height:'60%',
width:24,
// alignSelf:'center',
}
});
Try it out here
You can surround the Views with a parent View like so:
<View style={{ width: '100%', justifyContent: 'center', alignItem: 'center' }}>
//horizontal
<View style={{ zIndex: 1, elevation: 1, width: '100%', height: '20'% }}></View>
//vertical
<View style={{ zIndex: 0, elevation: 0, height: '100%', width: '20%' }}></View>
</View>
This will adjust dynamically depending on screen size since all height and width values are set using percentages.

React Native - Image inside Nested Text, Vertical Align not working

const styles = StyleSheet.create({
container: {
fontSize: 15,
alignItems: 'center',
justifyContent: 'center',
},
insideText: {
width: 30,
height: 30,
alignSelf: 'center',
},
})
<Text style={styles.container}>
<Image style={styles.insideText} source={myImage} />
test
</Text>
When I implement this functionality with Swift
Fixed by setting NSAttachment bounds.
But React Native does not know how to access those parameters.
The output of my code.
How do I center text and images?
can not divide a view into several.
Because the content is flexible, it is not known how many it will be.
Smaller image sizes will center them
The image is too small.
I want to keep the image size.
It's probably not the nicest way but you could do this:
const styles = StyleSheet.create({
container: {
fontSize: 15,
height: 30,
paddingTop: (30 - 15) / 2,
paddingLeft: 30
},
insideText: {
width: 30,
height: 30,
position: 'absolute',
left: 0,
top: 0,
},
})
Not exactly sure what you mean by the requirement of flexible content, but nesting an Image within a text does not seem like the way to go.
You'll have less styling flexibility, and are very limited.
To affect what you want without setting absolute positioning, just wrap it and have the icon and text as siblings of a parent View:
<View
style={{
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
}}>
<Image style={styles.insideText} source={snackIcon} />
<Text style={styles.container}>test</Text>
</View>
Fortunately your styles for insideText and container are fine for this example :)
Here's a snack of the code:
https://snack.expo.io/#paullyfire/centered-image-text-container
Let me know if you have any issues.

Border radius has weird edges - react native

When I style a TouchableOpacity like below, I get strange rendering in the iPhone 6 simulator. Any idea why?
Styles:
buttonContainer: {
height: 50,
borderColor: black,
borderRadius: 25,
margin: 2,
justifyContent: 'center',
backgroundColor: coral
}
Component:
<TouchableOpacity style={styles.buttonContainer}
onPress={this.signIn}
>
<Text style={styles.button}>Sign in</Text>
</TouchableOpacity>
Turns out the text had its own background color. Made it transparent and it fixed it.
Try adding overflow: hidden to your styles. Or try removing the margin.

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>

How to stretch a static image as background in React Native?

I'd like to use a background image in my react native app,
the image is smaller than the screen, so I have to stretch it.
but it doesn't work if the image is loaded from asset bundle
var styles = StyleSheet.create({
bgImage: {
flex: 1,
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'stretch',
resizeMode: 'stretch',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
}
});
<Image source={require('image!background')} style={styles.bgImage}>
<Text style={styles.welcome}>
Welcome to React Native!
</Text>
</Image>
it looks like this:
however, it works fine for a remote image, through source={{uri: 'background-image-uri'}}:
From Github issue: Image {require} is broken in React Native for Resizing, you could try <Image style={{width: null, height: null}}, hope that facebook would fix it soon.
The Image tag should generally not be treated as a container view.
Having an absolutely positioned wrapper containing your (stretched/contained) image appears to work well:
var styles = StyleSheet.create({
bgImageWrapper: {
position: 'absolute',
top: 0, bottom: 0, left: 0, right: 0
},
bgImage: {
flex: 1,
resizeMode: "stretch"
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10
}
});
<View style={{ flex: 1 }}>
<View style={styles.bgImageWrapper}>
<Image source={require('image!background')} style={styles.bgImage} />
</View>
<Text style={styles.welcome}>
Welcome to React Native!
</Text>
</View>
You could always use the Dimensions module to get the width of the screen and set your image's width style to that value:
var Dimensions = require('Dimensions');
var {width, height} = Dimensions.get('window');
It also seems strange that a remote image works fine...you can try loading up a local static image with the uri syntax by using source={{uri: 'local_image_file_name' isStatic: true}}.
for me use undefined instead of null value. on typescript environment, it will be prompted not assignable
bgImage: {
flex: 1,
width: undefined,
height: undefined,
resizeMode: 'stretch',
},