Image overlapping in react native - react-native

I am using absolute position to overlap a component over an image. There is another component after it which is a view with an orange colored background. It goes behind the absolute positioned component. How can keep it after the absolute positioned component (the height of this component might vary so I cannot use margin or height etc here)?
Have a look at the snack: https://snack.expo.io/#codebyte99/overlap-test
export default class App extends React.Component {
render() {
return (
<View style={styles.container}>
<Image
source={{
uri: 'https://facebook.github.io/react/logo-og.png',
cache: 'only-if-cached',
}}
style={{width: 400, height: 100}}
/>
<View style={styles.overlap}>
<Text>Event1</Text>
<Text>Event2</Text>
<Text>Event3</Text>
<Text>Event4</Text>
<Text>Event5</Text>
<Text>Event6</Text>
<Text>Event7</Text>
</View>
<View style={{ backgroundColor: 'orange', height: 200, width: 500 }}/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
},
overlap: {
width: 300,
backgroundColor: 'red',
borderColor: 'red',
borderWidth: 1,
position: 'absolute',
top: 80,
zIndex: 9999,
overflow: 'visible'
},
});
How it looks now:
what I want:

Do the orange and red box in one container and set this to an absolute position:
<View style={{position: "absolute", flexDirection:"column"}}
<View style={styles.YourStyleWithoutPositionAbsolute}>
<Text>Event1</Text>
<Text>Event2</Text>
<Text>Event3</Text>
<Text>Event4</Text>
<Text>Event5</Text>
<Text>Event6</Text>
<Text>Event7</Text>
</View>
<View style={{ backgroundColor: 'orange', height: 200, width: 500 }}/>
</View>

Related

Place Item to Bottom React Native

I'm creating a react native app i have a item - a plus button(shown in image)
I want this to the bottom of my page onto footer -
but the problem is that when i place this button on bottom with position: 'absolute', bottom: 0 it's only going to the bottom of the hero section & not to the footer
Code -
<View style={styles.main}>
<View style={styles.hero}>
<View style={styles.flex}>
<View style={styles.container}>
</View>
</View>
<View style={styles.flex2}>
</TouchableOpacity>
</View>
<View style={styles.container12}>
</View>
</View>
</View>
<TouchableOpacity>
<View style={styles.container33}>
<EntypoIcon name="plus" style={styles.icon28}></EntypoIcon>
</View>
</TouchableOpacity>
Main Styles -
main: {
width: '100%',
height: '100%',
},
hero: {
alignSelf: 'stretch',
height: 250,
backgroundColor: '#fff',
borderBottomLeftRadius: 50,
borderBottomRightRadius: 50,
},
container33: {
width: 50,
height: 50,
backgroundColor: '#1DA6FA',
// flex: 1,
borderRadius: 50,
position: 'absolute',
bottom: 0,
right: 10,
alignItems: 'center',
justifyContent: 'center'
},
The problem si that you are applying the absolute css position to the View inside the TouchableOpacity and not to the TouchableOpacity itself.
To achieve what you want to do, you should write something like:
<View style={styles.absoluteOpacity}>
<TouchableOpacity>
<View style={styles.container33}>
<EntypoIcon name="plus" style={styles.icon28}></EntypoIcon>
</View>
</TouchableOpacity>
</View>
And then the css:
container33: {
width: 50,
height: 50,
backgroundColor: '#1DA6FA',
// flex: 1,
borderRadius: 50,
right: 10,
alignItems: 'center',
justifyContent: 'center'
},
absoluteOpacity: {
position: 'absolute',
bottom: 0,
}

Vertically center image that's not affected by KeyboardAwareScrollView in React Native

Alright, so this has got me busy for quite a few hours already. I am trying to create a login screen where the main components are rendered on the bottom, with the logo in the remaining space. This is kind of what I would like to achieve:
To support my textinputs, I use KeyboardAwareScrollView, as it works better for me as opposed to KeyboardAvoidingView. My code currently looks like this (I plan on using a background image with a 50% color overlay rather than the red background, so the ImageBackground has to stay in place too):
<ImageBackground
source={require('./assets/img/background-clouds.png')}
resizeMode="cover"
style={styles.backgroundImage}>
<View style={styles.backgroundOverlay} />
<View style={styles.dummyView}>
<Text>elloha</Text>
</View>
<Image
source={require('./assets/img/logo.png')}
style={styles.backgroundLogo}
resizeMode="contain"
/>
<KeyboardAwareScrollView
keyboardShouldPersistTaps="always"
keyboardOpeningTime={0}
alwaysBounceHorizontal={false}
alwaysBounceVertical={false}
contentInsetAdjustmentBehavior="automatic"
showsHorizontalScrollIndicator={false}
showsVerticalScrollIndicator={false}
automaticallyAdjustContentInsets={false}
extraScrollHeight={30}
enableOnAndroid>
<StatusBar
backgroundColor="transparent"
barStyle="light-content"
hidden={false}
translucent
/>
<TouchableWithoutFeedback
onPress={Keyboard.dismiss}
accessible={false}>
<View style={styles.content}>
<View style={styles.backgroundContainer}>
<SafeAreaView style={{ flex: 0 }} />
<View style={styles.loginContainer}>
<View style={styles.loginScreen}>
// textinputs and buttons go here
</View>
<SafeAreaView style={{ backgroundColor: 'white' }} />
</View>
<View
style={{
backgroundColor: 'white',
height: Dimensions.get('window').height,
position: 'absolute',
width: Dimensions.get('window').width,
top: Dimensions.get('window').height,
}}
/>
</View>
</View>
</TouchableWithoutFeedback>
</KeyboardAwareScrollView>
</ImageBackground>
Relevant styles:
const styles = StyleSheet.create({
container: {
backgroundColor: "white",
},
content: {
flex: 1,
},
backgroundImage: {
flex: 1,
position: "absolute",
top: 0,
bottom: 0,
left: 0,
right: 0,
width: Dimensions.get("window").width,
height: Dimensions.get("window").height,
},
backgroundContainer: {
justifyContent: "flex-end",
flex: 1,
width: Dimensions.get("window").width,
height: Dimensions.get("window").height,
},
backgroundOverlay: {
backgroundColor: "red",
position: "absolute",
top: 0,
left: 0,
right: 0,
bottom: 0,
},
logoContainer: {
top: "10%",
width: "100%",
},
backgroundLogo: {
alignSelf: "center",
position: "absolute",
width: 126,
height: 96,
},
dummyView: {
backgroundColor: "red",
flex: 1,
},
loginContainer: {
borderTopEndRadius: 30,
borderTopStartRadius: 30,
width: "100%",
backgroundColor: "white",
height: 500,
alignItems: "center",
paddingTop: Dimensions.get("window").width * 0.1,
},
loginScreen: {
width: "80%",
backgroundColor: "white",
},
});
This yields the following result:
I can get it done by adding top: 160 to the backgroundLogo style, but that's a fixed value. I want it to be always in the center of the available space, but I'm unable to add a view between the background and the loginContainer, as all the logic for the keyboard and such is handled in between.
Is there a way to achieve what I want? Ideally, I should also be able to check the available height, and only show the logo if there is enough space (e.g. available height > 100, otherwise don't show logo).
Important:
I want the logo to stay fixed, so if the keyboard is shown, the logo should not move up. The loginContainer should go "over" the logo
EDIT:
Wrap Image inside a View with this style and give the loginContainer style height: '70%' :
...
<View style={styles.dummyView}>
<Text>elloha</Text>
</View>
<View
style={{
justifyContent: 'center',
alignItems: 'center',
height: '30%',
position: 'absolute',
width: '100%',
}}>
<Image
source={require('./assets/img/logo.png')}
style={styles.backgroundLogo}
resizeMode="contain"
/>
</View>
<KeyboardAwareScrollView
keyboardShouldPersistTaps="always"
...
...
loginContainer: {
borderTopEndRadius: 30,
borderTopStartRadius: 30,
width: '100%',
backgroundColor: 'orange',
height: '70%',
alignItems: 'center',
paddingTop: Dimensions.get('window').width * 0.1,
},
...
hie! I think using Dimension to get a specific screen's height and deciding it has 70% of the screen covered via form sheet and rest is free for a logo to be in and we can ask it to be down a little using rest of height's 50% as margin-top ( the image will be in the center of that image )
here is a SNACK LINK to see your example working with my suggested solution.
here is the draft code:
import * as React from 'react';
import { Text, View, StyleSheet, Dimensions, ImageBackground,TextInput,
Image, TouchableWithoutFeedback, Keyboard, SafeAreaView, StatusBar} from 'react-native';
import Constants from 'expo-constants';
import {KeyboardAwareScrollView} from 'react-native-keyboard-aware-scroll-view';
export default function App() {
return (
<ImageBackground
source={{
uri: 'https://cdn.pixabay.com/photo/2021/08/23/18/37/tea-6568547_960_720.jpg',
}}
resizeMode="cover"
style={styles.backgroundImage}>
<View style={styles.backgroundOverlay} />
<Image
source={require('./assets/snack-icon.png')}
style={styles.backgroundLogo}
resizeMode="contain"
/>
<KeyboardAwareScrollView
keyboardShouldPersistTaps="always"
keyboardOpeningTime={0}
alwaysBounceHorizontal={false}
alwaysBounceVertical={false}
contentInsetAdjustmentBehavior="automatic"
showsHorizontalScrollIndicator={false}
showsVerticalScrollIndicator={false}
automaticallyAdjustContentInsets={false}
extraScrollHeight={30}
enableOnAndroid>
<StatusBar
backgroundColor="transparent"
barStyle="light-content"
hidden={false}
translucent
/>
<TouchableWithoutFeedback onPress={Keyboard.dismiss} accessible={false}>
<View style={styles.content}>
<View style={styles.backgroundContainer}>
<SafeAreaView style={{flex: 0}} />
<View style={styles.loginContainer}>
<View style={styles.loginScreen}>
<TextInput value={'email'} style={{borderBottomWidth:1, padding:10}}/>
<TextInput value={'password'} style={{borderBottomWidth:1, padding:10}}/>
</View>
<SafeAreaView style={{backgroundColor: 'white'}} />
</View>
<View
style={{
backgroundColor: 'white',
height: Dimensions.get('window').height,
position: 'absolute',
width: Dimensions.get('window').width,
top: Dimensions.get('window').height,
}}
/>
</View>
</View>
</TouchableWithoutFeedback>
</KeyboardAwareScrollView>
</ImageBackground>
);
}
const styles = StyleSheet.create({
container: {
backgroundColor: 'white',
},
content: {
flex: 1,
},
backgroundImage: {
flex: 1,
position: 'absolute',
top: 0,
bottom: 0,
left: 0,
right: 0,
width: Dimensions.get('window').width,
height: Dimensions.get('window').height,
},
backgroundContainer: {
justifyContent: 'flex-end',
flex: 1,
width: Dimensions.get('window').width,
height: Dimensions.get('window').height,
},
backgroundOverlay: {
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
},
logoContainer: {
top: '10%',
width: '100%',
},
backgroundLogo: {
alignSelf: 'center',
position: 'absolute',
marginTop: Dimensions.get('window').height/7, // top for rest of the screen to push logo down
width: 126,
height: 96,
},
dummyView: {
backgroundColor: 'red',
flex: 1,
},
loginContainer: {
borderTopEndRadius: 30,
borderTopStartRadius: 30,
width: '100%',
backgroundColor: 'white',
height: Dimensions.get('window').height/1.5, //container of form height
alignItems: 'center',
paddingTop: Dimensions.get('window').width * 0.1,
},
loginScreen: {
width: '80%',
backgroundColor: 'white',
},
});
Here is the output of code on android/ios:

Scroll doesn't work with ScrollView and absolute positioned component

I have a scrollView and a component with absolute position. The scrollView doesn't scroll at all. Have a look at the code: https://snack.expo.io/#codebyte99/overlap-test
<ScrollView contentContainerStyle={{ flex: 1 }}>
<View style={styles.container}>
<Image
source={{
uri: 'https://facebook.github.io/react/logo-og.png',
cache: 'only-if-cached',
}}
style={{width: 400, height: 100}}
/>
<View style={styles.overlap}>
<Text>Event1</Text>
<Text>Event2</Text>
<Text>Event3</Text>
<Text>Event4</Text>
<Text>Event5</Text>
<Text>Event6</Text>
<Text>Event7</Text>
<View style={{ backgroundColor: 'orange', height: 800, width: 500 }}/>
<View style={{ backgroundColor: 'green', height: 800, width: 500 }}/>
</View>
</View>
</ScrollView>
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
},
overlap: {
width: 300,
backgroundColor: 'red',
borderColor: 'red',
borderWidth: 1,
position: 'absolute',
top: 80,
zIndex: 9999,
overflow: 'visible'
},
});
If the flex is not used in scrollView, the absolute positioned component are not visible completely and if it is used, the scroll doesn't work.
With flex: 1, the ScrollView container takes all available space, however this does not include the items positioned absolutely inside it since they are out of the document flow.
So you should remove it, and instead you should give the container style enough height to display every item inside:
container: {
flex: 0,
alignItems: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
height: 2000,
},
Did you try to change flex: 1 to flexGrow: 1 in contentContainerStyle.

How to align both the Components in same in React Native

I have created a progress bar in which i have rotated it to 90 degrees to make it vertical bar and then i have taken an battery image and tried to place the progress bar inside the battery but i couldn't able to place the image inside by using the position relative.
But when i use the position to be absolute the images gets aligned but i couldn't use paddingTop or PaddingBottom.
render() {
console.log("Progrss bar");
const barWidth = Dimensions.get("screen").width - 30;
const batteryWidth = Dimensions.get("screen").width;
const progressCustomStyles = {
backgroundColor: "red",
borderRadius: 0,
borderColor: "orange"
};
return (
<View style={styles.container}>
<View style={styles.angle}>
<View style={styles.progress}>
<ProgressBarAnimated
width={barWidth}
value={this.state.progress}
height={150}
borderRadius={0}
backgroundColor={
this.state.progress > 20 && this.state.progress < 90
? "yellow"
: this.state.progress >= 90
? "green"
: "red"
}
/>
</View>
<Image
style={{
width: batteryWidth,
height: 150,
position: "relative",
zIndex: 1
}}
source={require("./assets/battery.png")}
/>
</View>
</View>
);
Styles Used:
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
backgroundColor: "#FFFFFF"
},
angle: {
transform: [{ rotate: "-90deg" }]
},
progress: {
height: 100
}
});
Output i got:
It's going to be tedious to align an element perfectly inside of an image because any layout properties applied to the image will only conform to the bounding dimensions of the image. Since your image looks like two rectangles, you could try drawing it with Views instead. Example:
render() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<View style={{ height: 20, width: 50, borderWidth: 5, borderBottomWidth: 0 }} />
<View style={{ height: 200, width: 100, borderWidth: 5, justifyContent: 'flex-end' }}>
<View style={{ height: 75, backgroundColor: 'green' }} />
</View>
</View>
);
}

In React Native, how do I put a view on top of another view, with part of it lying outside the bounds of the view behind?

I'm trying to make a layout as per below with React Native.
How do I specify the position of B relative to A?
With iOS Interface Builder and autoconstraints, this can very explicitly be done and is a breeze. It's not so obvious how one might achieve this with React Native.
Add the following style to the "floating" view:
position: 'absolute'
You may also need to add a top and left value for positioning.
The above solutions were not working for me. I solved it by creating a View with the same background colour as the parent and added negative margin to move the image upwards.
<ScrollView style={{ backgroundColor: 'blue' }}>
<View
style={{
width: '95%',
paddingLeft: '5%',
marginTop: 80,
height: 800,
}}>
<View style={{ backgroundColor: 'white' }}>
<Thumbnail square large source={{uri: uri}} style={{ marginTop: -30 }}/>
<Text>Some Text</Text>
</View>
</View>
</ScrollView>
and I got the following result.
You can use zIndex for placing a view on top of another. It works like the CSS z-index property - components with a larger zIndex will render on top.
You can refer: Layout Props
Snippet:
<ScrollView>
<StatusBar backgroundColor="black" barStyle="light-content" />
<Image style={styles.headerImage} source={{ uri: "http://www.artwallpaperhi.com/thumbnails/detail/20140814/cityscapes%20buildings%20hong%20kong_www.artwallpaperhi.com_18.jpg" }}>
<View style={styles.back}>
<TouchableOpacity>
<Icons name="arrow-back" size={25} color="#ffffff" />
</TouchableOpacity>
</View>
<Image style={styles.subHeaderImage} borderRadius={55} source={{ uri: "https://upload.wikimedia.org/wikipedia/commons/thumb/1/14/Albert_Einstein_1947.jpg/220px-Albert_Einstein_1947.jpg" }} />
</Image>
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "white"
},
headerImage: {
height: height(150),
width: deviceWidth
},
subHeaderImage: {
height: 110,
width: 110,
marginTop: height(35),
marginLeft: width(25),
borderColor: "white",
borderWidth: 2,
zIndex: 5
},
You can use this OverlayContainer. The trick is to use absolute with 100% size. Check below an example:
// #flow
import React from 'react'
import { View, StyleSheet } from 'react-native'
type Props = {
behind: React.Component,
front: React.Component,
under: React.Component
}
// Show something on top of other
export default class OverlayContainer extends React.Component<Props> {
render() {
const { behind, front, under } = this.props
return (
<View style={styles.container}>
<View style={styles.center}>
<View style={styles.behind}>
{behind}
</View>
{front}
</View>
{under}
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
height: '100%',
justifyContent: 'center',
},
center: {
width: '100%',
height: '100%',
alignItems: 'center',
justifyContent: 'center',
},
behind: {
alignItems: 'center',
justifyContent: 'center',
position: 'absolute',
left: 0,
top: 0,
width: '100%',
height: '100%'
}
})
import React, {Component} from 'react';
import {StyleSheet, View} from 'react-native';
export default class App extends Component {
render() {
return (
<View>// you need to wrap the two Views an another View
<View style={styles.box1}></View>
<View style={styles.box2}></View>
</View>
);
}
}
const styles = StyleSheet.create({
box1:{
height:100,
width:100,
backgroundColor:'red'
},
box2:{
height:100,
width:100,
backgroundColor:'green',
position: 'absolute',
top:10,
left:30
},
});
You can use react-native-view-overflow plugin for placing a view on top of another. It works like the CSS z-index property.
import ViewOverflow from 'react-native-view-overflow';
<ViewOverflow />
<View style={[styles2.cardBox, { marginTop: 50 }]}>
<View style={[styles2.cardItem]} >
<Text style={styles2.cardHeader}>userList</Text>
</View>
<View style={[styles2.cardContent]}>
<Text style={styles2.text}>overflow: "visible"</Text>
</View>
<View style={[styles2.cardItemFooter]} >
<Text style={styles2.cardTextFooter}>...</Text>
</View>
</View>
</ViewOverflow>
const styles2 = StyleSheet.create({
cardBox: {
borderLeftWidth: 0,
borderTopWidth: 0,
backgroundColor: "transparent",
borderWidth: 1,
borderColor: "#d0d0d0",
width: '94%',
alignSelf: 'center',
height: 200,
position: "relative",
borderRadius: 15,
overflow: "visible" // doesn't do anything
},
cardContent: {
textAlign: "right",
backgroundColor: "transparent",
marginTop: 15,
alignSelf: 'flex-end',
padding: 5,
},
cardHeader: {
color: '#fff',
fontFamily: 'Vazir',
fontSize: 12
},
cardItem: {
backgroundColor: "#3c4252",
borderRadius: 3,
position: "absolute",
top: -10,
right: -5,
width: 50,
height: 20,
paddingRight: 5,
},
})
The easiest way to achieve this is with a negative margin.
const deviceWidth = RN.Dimensions.get('window').width
a: {
alignItems: 'center',
backgroundColor: 'blue',
width: deviceWidth,
},
b: {
marginTop: -16,
marginStart: 20,
},
You can use elevation property for Android if you don't mind the shadow.
{
elevation:1
}
Try this:
style = {{position: 'absolute', bottom: 20, left: 20, elevation: 100}}
Based on the example above i've created a component which stacks all childeren on top of each other. You could even nest OverlayContainers inside OverlayContainers.
Usage:
<OverlayContainer>
<View style={{backgroundColor:'red', width:150, height: 150}}></View>
<View style={{backgroundColor:'yellow', width:50, height: 50}}></View>
<Text>Just some text</Text>
</OverlayContainer>
Output:
import React, { FC, PropsWithChildren } from 'react'
import { StyleSheet, View } from 'react-native'
export const OverlayContainer: FC<PropsWithChildren<unknown>> = (props) => {
return (
<View style={styles.container}>
{props.children.map((child, index) => (
<View style={styles.child} key={index}>
{child}
</View>
))}
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
height: '100%',
},
child: {
position: 'absolute',
left: 0,
top: 0,
width: '100%',
height: '100%'
}
})
<SafeAreaView style={{ flex: 1 }} >
<View style={{ height: Dimensions.get('window').height / 2, backgroundColor: 'blue', justifyContent: 'center' }}>
<Text style={{ fontSize: 25, alignSelf: 'center' }} >A</Text>
<View style={{ justifyContent: 'center', height: 100, width: 100, backgroundColor: 'yellow', position: 'absolute', left: 20, top: Dimensions.get('window').height / 2 - 70 }}>
<Text style={{ fontSize: 22, alignSelf: 'center' }} >B</Text>
</View>
</View>
</SafeAreaView>