react native absolute positioning not working - javascript

My button in the code below is positioned absolutely but it isn't working. It is taking up space in its containing view and it is not allowing the image to be below it.
<View style={{
justifyContent: 'flex-end',
alignItems: 'center',
flexDirection: 'row',
flex: 0.5,
borderRadius: 8
}}>
<Image
style={mapStyles.avatar}
source={props.image} />
<Button
small
icon
style={{
positon: 'absolute',
right: -5,
top: -5,
width: 20,
height: 20,
zIndex: 50,
elevation: 10,
borderRadius: 10,
backgroundColor: '#FF3B3F',
shadowColor: '#000000',
shadowOffset: {
width: 0,
height: 1
},
shadowRadius: 1,
shadowOpacity: 1.0
}}
onPress={() => props.updateImage(null)}>
<Icon style={locationStyle.deleteLocationButtonIcon}
name="close-o" size={22} color="#9E9E9E" />
</Button>
</View>
The button is the pink bit:
The button needs to be in the top right corner of the image, It is a cancel button. The image should be to the far right where the button is. I have experienced absolute positioning not working in react native before. Is this a bug or am I doing it wrong?
image styles:
avatar: {
width: 100,
height: 100
}

Try nesting your button inside of the Image like
<Image>
<Button />
</Image

Related

How to vertically and horizontally align child components 'on top' of parent in React Native?

I'm having a lot of trouble getting two child components to vertically and horizontally align 'on top' of their parent element in React Native.
I am trying to place Loader and Button on top of RTCView.
I currently have this JSX returning in the parent:
if (localStream) {
return (
<View style={styles.videoViewWrapper}>
<RTCView style={styles.android} streamURL={localStream.toURL()} />
<View
style={{ justifyContent: 'center', position: 'absolute', }}
>
<Loader
title={callDetails}
>
</Loader>
<Button
mode="contained"
style={{ width: 150, margin: 100 }}
onPress={handleCancelCall}>
Cancel
</Button>
</View>
</View>
);
}
And this inside Loader:
Loader = props => {
return (
<>
<StatusBar
hidden
/>
<View style={{
flex: 1,
alignItems: 'center',
}}>
<Text
style={styles.text}
>
{props.title}
</Text>
<ProgressBar color={Colors.green800} indeterminate={true} style={{ width: 100, height: 1 }} />
</View>
</>
)
}
const styles = StyleSheet.create({
text: {
fontFamily: "Quicksand-Light",
fontSize: 22,
textAlign: "center",
color: "#333333",
marginBottom: 25,
justifyContent: 'center',
}
});
Whilst I have achieved getting Loader to display 'on top' of it's parent, I cannot move them to their position at the top of the screen.
Any help would be much appreciated!
Your absolute positioned View needs to cover its parent. You can achieve this by adding top: 0, left: 0, right: 0, bottom: 0 to its style
You may need to edit your Button style. I removed it from your code, add it if you need margin or a specific width.
<View style={{ justifyContent: 'center', alignItems: 'center', position: 'absolute', top: 0, left: 0, right: 0, bottom: 0 }}>
<Loader title={callDetails} />
<Button mode="contained" onPress={handleCancelCall}>Cancel</Button>
</View>

Trying to bring my button to the front, tried zIndex?

Trying to bring a button.js component to the front of my background carousel. Tried using zIndex, worked fine with my logo but not with my button?
Button code:
return (
<View style={styles.buttonContainer} >
<TouchableOpacity onPress={onPress} style={buttonStyle} >
<Text style={textStyle} >
{children}
</Text>
</TouchableOpacity>
</View>
);
const styles = {
buttonContainer: {
zIndex: 999,
alignItems: 'center'
},
buttonStyle: {
zIndex: 999,
position: 'absolute',
bottom: -200,
flex: .3,
alignSelf: 'auto',
backgroundColor: '#ffff00',
borderRadius: 10,
borderWidth: 1,
borderColor: '#000000',
marginLeft: 5,
marginRight: 5,
width: 250,
borderWidth: 1
},
textStyle: {
zIndex: 999,
alignSelf: 'center',
color: '#000000',
fontSize: 16,
fontWeight: '600',
paddingTop: 10,
paddingBottom: 10
}
};
export default Button;
Code for my app. Notice how i have literally added zIndex 999 for my button, and it still has not worked.
export default function App() {
return (
<View style={styles.carouselContainer}>
<BackgroundCarousel images={images}>
<View style={styles.logoContainer}>
<Image source={logo} style={styles.logo} />
<Text style={styles.logoText}>Hello World</Text>
</View>
<View>
<Button style={{ zIndex: 999 }}>
Let's Get Started
</Button>
</View>
</BackgroundCarousel>
</View>
);
}
const styles = StyleSheet.create({
carouselContainer: {
zIndex: 1,
height: "100%",
width: "100%",
backgroundColor: '#fff',
flex: 1
},
logoContainer: {
zIndex: 2,
alignItems: 'center',
position: 'absolute',
justifyContent: "center",
top: 0, left: 0, right: 0, bottom: 450
},
logo: {
zIndex: 2,
width: 125,
height: 125,
},
logoText: {
zIndex: 2,
color: 'black',
fontSize: 25,
fontWeight: '500',
borderColor: 'white',
fontFamily: "Baskerville-Bold",
},
button: {
flex: 1,
zIndex: 999,
}
});
Basically, is there another way to bring the button forward? Seeing as how zIndex is not working for me in this case.
z-index is only relative to that element's parent so as mentioned by #prakash-karena delete the view that surrounding your button.
<View style={styles.carouselContainer}>
<BackgroundCarousel images={images}>
<View style={styles.logoContainer}>
<Image source={logo} style={styles.logo} />
<Text style={styles.logoText}>Hello World</Text>
</View>
<Button style={{ zIndex: 999 }}>
Let's Get Started
</Button>
</BackgroundCarousel>
</View>
I believe zIndex is supported in the latest version of react native for iOS only, order that you place the elements in determines its layout order. you can try making overflow visible of scrollview.

Is there a way to create space between 2 elements without padding or margin?

I am using React Native and I have 2 inline buttons, the search and add buttons:
What I need is to create some space between these buttons without affecting the left and right edge.
This is how I am using the JSX:
<View style={globalStyles.stretchContent}>
<TouchableOpacity
style={[
globalStyles.touchableBtnDropOffItem,
{ backgroundColor: Colors.dropOffTabColor },
]}
>
<Text style={{ color: '#fff' }}>Search</Text>
</TouchableOpacity>
<TouchableOpacity
style={[
globalStyles.touchableBtnDropOffItem,
{ backgroundColor: Colors.dropOffTabColor },
]}
>
<Text style={{ color: '#fff' }}>Add</Text>
</TouchableOpacity>
</View>
And the stylesheet:
touchableBtnDropOffItem: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
alignContent: 'space-between',
height: 36,
marginTop: 20,
borderRadius: 2,
marginHorizontal: 5,
},
stretchContent: {
flex: 1,
color: white,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
},
As you know React Native uses flexbox and I am having a hard time trying to achieve what I need. The thing is that if I apply margin, it will reduce the width of the buttons on the end of each one. For example: I need the search button to be completely aligned with the text All Passengers List (9). If I apply marginHorizontal it will reduce the width, it will create a margin on both sides of the 2 buttons so it won't be aligned anymore with the text I mentioned.
So, what can I do in this case?
touchableBtnDropOffItem: {
alignItems: 'center',
justifyContent: 'center',
alignContent: 'space-between',
height: 36,
marginTop: 20,
borderRadius: 2,
flexBasis: 45%,
},
stretchContent: {
flex: 1,
color: white,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
},
add flexBasis: 45% to the button and add justifyContent: 'space-between' to the stretchContent.
flexBasis is something like width when used inside flexbox
The easiest way to fix this is, keep a width for both the button and use justifyContent: 'space-around' and if want space in between button's left or right too use justifyContent: 'space-between'.
For your example,
touchableBtnDropOffItem: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
alignContent: 'space-between',
height: 36,
marginTop: 20,
borderRadius: 2,
marginHorizontal: 5,
width: '40%'
},
stretchContent: {
flex: 1,
color: white,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
},
The simplest thing to do is set the buttons to have a width slightly less than half (45% or 40%), then float each button (float Search to the left, and Add to the right):
(I think the below syntax is correct - if it's not valid React code, please tell me how to fix it).
<View style={globalStyles.stretchContent}>
<TouchableOpacity
style={[
globalStyles.touchableBtnDropOffItem,
{ backgroundColor: Colors.dropOffTabColor; float: left; },
]}
>
<Text style={{ color: '#fff' }}>Search</Text>
</TouchableOpacity>
<TouchableOpacity
style={[
globalStyles.touchableBtnDropOffItem,
{ backgroundColor: Colors.dropOffTabColor; float: right; },
]}
>
<Text style={{ color: '#fff' }}>Add</Text>
</TouchableOpacity>
</View>
And in the stylesheet:
touchableBtnDropOffItem: {
width: 45%,
flex: 1,
alignItems: 'center',
justifyContent: 'center',
alignContent: 'space-between',
height: 36,
marginTop: 20,
borderRadius: 2,
marginHorizontal: 5,
},

React Native: How do I set a button to be at the level of 70% of the height of its parent?

Suppose I want to position a button 30% of the way the down its parent element (i.e. the whole page) in React Native. How do I do this using Flexbox or some other method?
For example, adding justifyContent: 'center' to the parent element would work if I wanted the button to be 50% of the way down the page.
Here is my React layout / stylesheet:
<View style={styles.container}>
<LinearGradient colors={['#e80ca3', '#e500ff', '#950ce8']} style={styles.linearGradient}>
<View style={styles.scanContainer}>
<View style={styles.scanButton} />
</View>
</LinearGradient>
</View>
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
linearGradient: {
flex: 1,
alignSelf: 'stretch',
justifyContent: 'center', // What to put here to make `scanContainer` 30% instead of 50% of the way down?
},
scanContainer: {
alignSelf: 'center',
},
scanButton: {
width: 175,
height: 175,
borderRadius: 87.5,
backgroundColor: 'green',
},
});
Here's the solution using flex properties
linearGradient: {
flex: 1,
alignSelf: 'stretch', //... Remove justifyContent: 'center',
},
scanContainer: {
flex: 0.7,
justifyContent: 'flex-end', // 30 % from the bottom
alignSelf: 'center',
},
You can add an empty View with flex 0.7 above the button:
<View style={{ flex: 1 }}>
<View style={{ flex: 0.7 }} />
<Button title="button" />
</View>
You can use absolute positioning for the button container.
scanContainer: {
alignSelf: 'center',
position: 'absolute',
bottom: '30%',
left: 0
}
Using flex:
<View style={[styles.scanContainer,{flex:1}]}>
<View style={{flex:1}} />
<View style={styles.scanButton} />
<View style={{flex:2}} />
</View>
Using Dimension:
import {Dimensions} from 'react-native';
<View style={[styles.scanButton,{marginTop:Dimensions.get('window').height * 0.3}]} />

React Native - how to catch touch events behind an absolute position component

I'm trying to have a popup dialog (created as a component with position: 'absolute') and to close it when user clicks outside of the popup.
I'm new to React Native so other things I did might be wrong, forgive me for that :)
This is a screenshot of the popup when it is open
This is some of the code:
From the Popup component:
render() {
if (!this.props.open) {
return <View />
}
return (
<View style={styles.container}>
<View style={styles.popupStyle}>
<View style={{flex:1, justifyContent: 'center', marginRight: 10}}>
<View style={styles.amountEnterStyle}>
<TextInput
keyboardType={'numeric'}
underlineColorAndroid='transparent'
autoCorrect={false}
style={styles.textInputStyle}
value={this.state.amount}
onChangeText={this._onAmountEnter.bind(this)} />
<Text style={styles.currencyTextStyle}>NIS</Text>
</View>
<View style={styles.separatorStyle} />
<View style={styles.categorySectionStyle}>
{this._renderCategoryDropdown()}
</View>
</View>
<View style={{justifyContent: 'center'}}>
<TouchableWithoutFeedback
onPress={this._onAddPaymentClicked.bind(this)} >
<View style={{width: 110, height:100, backgroundColor: "#ff0000"}} />
</TouchableWithoutFeedback>
</View>
</View>
</View>
);
const styles = StyleSheet.create({
container: {
position: 'absolute',
top: 0,
bottom: 0,
left: 0,
right: 0,
width: undefined,
height: undefined,
justifyContent: 'center',
alignItems: 'center',
},
amountEnterStyle: {
justifyContent: 'center',
alignItems: 'center',
flexDirection: 'row'
},
textInputStyle: {
width: 100,
fontSize: 50,
fontWeight: 'bold',
height: 65,
flex: 1,
marginTop: -20,
paddingBottom: 0,
marginBottom: 0,
marginLeft:10,
textAlignVertical: 'center'
},
currencyTextStyle: {
fontSize: 50,
color: '#c0c0c0',
marginTop: -20,
textAlignVertical: 'center'
},
separatorStyle: {
height: 2,
marginTop: 0,
backgroundColor: '#c0c0c0',
},
categorySectionStyle: {
justifyContent: 'flex-start',
flexDirection: 'row',
alignItems: 'flex-start',
marginTop: 8
},
categoryColorDotStyle: {
width: 20,
height: 20,
borderRadius: 100/2,
marginLeft: 10,
marginTop: 5,
},
categoryTextStyle: {
fontSize: 24,
marginHorizontal: 4,
color: '#c0c0c0',
marginLeft: 10,
paddingRight: 10,
marginTop: -3
},
popupStyle: {
width: Dimensions.get('window').width - 60,
flexDirection: 'row',
justifyContent: 'space-between',
height: 150,
paddingRight:10,
paddingLeft:10,
borderRadius: 2,
margin: 20,
padding: 10,
opacity: 1,
borderRadius: 10,
backgroundColor: '#ffffff'
},
dropdownSeparator: {
height: 1,
backgroundColor: 'cornflowerblue'
},
And this is the hosting component:
render() {
var totalIncome = this.props.balance.totalIncome;
var totalExpanses = this.props.balance.totalExpanses;
return (
<View style={{flex:1, justifyContent: 'space-between'}}>
<Image pointerEvents='none' source={require('../../res/background.png')} style={styles.container} />
<MainScreenHeader onSettingPress={this._onBalanceSettingsPress.bind(this)}/>
<MainBalanceCounter totalCount={totalIncome} currentCount={totalIncome-totalExpanses} />
<View style={{justifyContent: 'center', alignItems: 'center', marginBottom: 150}}>
<AddPaymentButton onPress={this._onAddPaymentPress.bind(this)} />
<PaymentPopup
open={this.state.paymentPopupOpen}
onAddPaymentClicked={this._onPaymentPopupAddClicked.bind(this)} />
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
width: undefined,
height: undefined,
backgroundColor:'transparent',
justifyContent: 'center',
alignItems: 'center',
},
innerContainer: {
justifyContent: 'space-around',
alignItems: 'center',
flex: 1,
backgroundColor: 'transparent'
},
});
I was trying man things to have a view that will catch clicks that happens outside of the popup, but no success.
Any help will be much appreciated,
Thanks,
Giora.
have you tried out react-native-modalbox? I use it in my applications and it works pretty great. If you have touch events behind the modal, it will close. Also, you can define how large you'd like the modal to be. It doesn't have to take up the whole screen.
Otherwise, you were on the right track. You'd need a TouchableWithoutFeedback component that covers the full width and height of the screen. Your popup would be alongside of this component with a higher zIndex. Let me know if you'd like to go this route and I can provide more advice. Cheers!

Categories

Resources