Unable to position element to the right - react-native

I have a few elements on my app screen and I want the last one to be positioned towards the bottom-right (I'm using the Expo client on Android). Here's the render() function from App.js:
render() {
return (
<View style={styles.container}>
<StatusBar
hidden={true}
/>
<TodoItem/>
<TodoItem/>
<TodoItem/>
<AddTodoButton style={styles.button}/>
</View>
);
}
So, it's the <AddTodoButton\> that I want to position. Here's the styles I'm using:
const styles = StyleSheet.create({
container: {
backgroundColor: '#fcf7e2',
height: '100%',
},
button: {
position: 'absolute',
bottom: 0,
right: 0,
}
});
The code for AddTodoButton is as follows:
const Button = () => (
<Text style={styles.button}>+</Text>
);
const styles = StyleSheet.create({
button: {
fontSize: 30,
paddingLeft: 21,
paddingTop: 7,
width: 60,
height: 60,
backgroundColor: '#FF4456',
borderRadius: 60/2,
overflow: 'hidden',
}
});
I've tried several variations of styles for the button property, but the element doesn't respond and is stuck to the left edge right after the three <TodoItem/> (which are nothing but <Text> as of now).
I'm happy doing this in Flexbox, except that I don't know how to and managed to mess up the layout completely when I tried. :|
Any thoughts?

See if simply adding flex:1 to container style works, if not try the following
render() {
return (
<View style={styles.container}>
<StatusBar
hidden={true}
/>
<TodoItem/>
<TodoItem/>
<TodoItem/>
<View style={styles.buttonContainer}>
<AddTodoButton style={styles.button}/>
</View>
</View>
);
}
// In your styles, do the following
container: {
flex: 1
}
buttonContainer{
flex: 1,
flexDirection: 'row',
justifyContent: 'flex-end',
alignItems: 'flex-end',
alignSelf: 'flex-end'
}
Not sure about your AddTodoButton but I'd recommend looking there to see if that's the one not pushing things to the right.

I think you just simply did not apply the style to your button:
const Button = (props) => (
<Text style={[styles.button,props.style]}>+</Text>
);
const styles = StyleSheet.create({
button: {
fontSize: 30,
paddingLeft: 21,
paddingTop: 7,
width: 60,
height: 60,
backgroundColor: '#FF4456',
borderRadius: 60/2,
overflow: 'hidden',
}
});

Related

Touchable Opacity messes up width in row container

I'm trying to make these two Card components appear next to each other in a row as shown
here which seems to work when I wrap the component in a View, but appears like this with a bunch of unnecessary space in between when I try it with a TouchableOpacity.
Here is my code for the Card component (currently with TouchableOpacity on and the View wrapper commented out):
export const NavCard = ({
title,
height = 200,
onPress = null,
background = null,
}) => {
return (
<TouchableOpacity
onPress={onPress}
style={[
{ height: height },
background ? styles.cardImage : styles.noImage,
]}
>
{/* <View
style={[
{ height: height },
background ? styles.cardImage : styles.noImage,
]}
> */}
<Image
source={background}
resizeMode="cover"
style={{
height: height,
width: "100%",
borderRadius: 15,
position: "absolute",
top: 0,
right: 0,
}}
/>
<View style={{ padding: 15 }}>
<Text style={styles.title}>{title}</Text>
<Image
style={styles.arrow}
source={require("../assets/arrow-right.png")}
/>
</View>
{/* </View> */}
</TouchableOpacity>
);
};
const styles = StyleSheet.create({
cardImage: {
flexGrow: 1,
margin: "2%",
borderRadius: 15,
},
noImage: {
flexGrow: 1,
margin: "2%",
borderRadius: 15,
backgroundColor: "#333436",
},
title: {
fontSize: 24,
color: "#E4E5EA",
fontWeight: "bold",
shadowColor: "#000000",
shadowOffset: { width: 2, height: 2 },
shadowOpacity: 1,
shadowRadius: 4,
},
arrow: {
width: 15,
height: 15,
resizeMode: "contain",
position: "absolute",
top: 22,
right: 20,
},
});
Here is the code for the screen:
const HomeScreen = ({ navigation }) => {
return (
<View style={styles.container}>
<View style={styles.rowContainer}>
<NavCard
title="Map"
height={180}
onPress={() => navigation.navigate("Map")}
background={require("../assets/pvdx1.png")}
></NavCard>
<NavCard
title="CAD"
height={180}
background={require("../assets/pvdx1.png")}
onPress={() => navigation.navigate("CADScreen")}
></NavCard>
</View>
</View>
);
};
const styles = StyleSheet.create({
container: {
paddingTop: 10,
padding: 4,
flex: 1,
},
rowContainer: {
flexDirection: "row",
justifyContent: "space-between",
},
body: {
paddingTop: 10,
fontSize: 16,
color: "#E4E5EA",
},
});
export default HomeScreen
Does anyone know why it's messing up the width of both components if the styles of the View and TouchableOpacity are exactly the same? I'm using React Native.
Edit: Have updated to use Image instead of ImageBackground (code now reflects this), but the result is the same.
I figured out the issue: I was importing TouchableOpacity from react-native-gesture-handler instead of react-native. Changed it and it works just fine.
Probably the problem is in your <ImageBackground /> , Because I replaced that with native <Image /> and it's working. here is how my Image looks, you can compare with your code:
<Image
style={{
height: height,
borderRadius: 15,
position: "absolute",
top: 0,
right: 0,
width: "100%"
}}
resizeMode="cover"
source={{ uri: "https://via.placeholder.com/250x150" }}
/>
Here you can check the working code
for me i had to also set the width on the TouchableOpacity (and the view within)
<TouchableOpacity
style={{flex: 1, width: '100%'}}

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'}
});

how to create a component that will show the score

score image enter image description here
I want to create a component in react-native which will display the score, the score can be different i.e it can be 65 or 45. Please go through the image link.
try this
const ScoreComponent = (props) => {
return <View style={{backgroundColor:"white",width:50,height:50,borderRadius:25,borderWidth:1,borderColor:"red",alignItems:"center",justifyContent:"Center"}}>
<Text style={{color:"blue"}}>{props.score}</Text>
</View>
}
and use like this
<ScoreComponent score={65} />
snack link https://snack.expo.io/#mehran.khan/score
I modified #Mehran Khan 's answer to include the orange quarter sphere in the background.
https://snack.expo.io/ZMjTm5ONv
const ScoreComponent = (props) => {
return <View style={{backgroundColor:"white",width:50,height:50,borderRadius:25,borderWidth:1,borderColor:"red",alignItems:"center",justifyContent:"Center"}}>
<Text style={{color:"blue"}}>{props.score}</Text>
</View>
}
const ScoreContainer = () => {
return <View style={{overflow: 'hidden', width: 55, height: 55, justifyContent: 'center', alignItems: 'center'}}><ScoreComponent score={65} />
<View style={{zIndex: -10, width: 90, height: 90, borderRadius: 100, position: 'absolute', left: -45, bottom: -45, backgroundColor: 'rgba(240,100,0,0.3)'}}/>
</View>;
}
export default function App() {
return (
<View style={styles.container}>
<ScoreContainer />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
alignItems:"center",
overflow: 'hidden',
},
});

react native 2 colors as background

I'm trying to make 2 colors of background using flex, and it seems to work good but I want to make the button on the middle as in the photo, where I need to insert the button in the code?
i want it to be like this:
return (
<View style={container}>
<View style={leftContainer}>
</View>
<View style={rightContainer}>
</View>
<Button
title="button"/>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection:'row'
},
leftContainer:{
flex:1,
backgroundColor: '#ca8afa',
},
rightContainer:{
flex:1,
backgroundColor: '#96d0e3'
},
addButton: {
justifyContent: 'center',
alignItems: 'center',
position: 'absolute',
bottom: 20,
right: 20,
zIndex: 1111,
width: calcSize(192 / 2),
height: calcSize(192 / 2)
}
})
the problem is that the button is also in the row now and not in the middle,
how can i fix it?
Here's a live demo of a possible solution: https://snack.expo.io/HJFL7A3ez
Edit - Adding the code here as well:
export default class App extends Component {
render() {
return (
<View style={styles.container}>
<View style={styles.leftContainer}>
</View>
<View style={styles.rightContainer}>
</View>
<View style={styles.buttonContainer}>
<Button style={styles.addButton} title="button"/>
</View>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection:'row'
},
leftContainer:{
flex:1,
backgroundColor: '#ca8afa',
},
rightContainer:{
flex:1,
backgroundColor: '#96d0e3'
},
buttonContainer: {
position: 'absolute',
width: '100%',
height: '100%',
justifyContent: 'center',
alignItems: 'center',
},
addButton: {
zIndex: 1111,
width: 200
}
})

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>