React Native: How to stretch TouchableOpacity - react-native

I am trying to have two large buttons (TouchableOpacity) be next to each other and take up 50% of the width of the screen.
But they only seem to be as wide as the Text component within them.
How can I make the two TouchableOpacity take up the full width of the screen, with each taking up 50% of the width?
const styles = StyleSheet.create({
container: {
flexDirection: 'row',
backgroundColor: 'lightblue',
height: 200,
justifyContent: 'space-around',
},
btn: {
flex: 1,
backgroundColor: 'red',
justifyContent: 'center',
padding: 20,
borderWidth: 1,
},
});
return (
<View style={styles.container}>
<TouchableOpacity style={styles.btn}>
<Text>Left</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.btn}>
<Text>Right</Text>
</TouchableOpacity>
</View>
);

Try to add a width of 50% to your btn class
const styles = StyleSheet.create({
container: {
flexDirection: 'row',
backgroundColor: 'lightblue',
height: 200,
justifyContent: 'space-around',
},
btn: {
width: '50%',
backgroundColor: 'red',
padding: 20,
borderWidth: 1,
},
});
You can also use dimensions from react native and put width: windowWidth/2 on your btn class.

A possible solution is to use react native's Dimensions
https://reactnative.dev/docs/dimensions
import { Dimensions } from 'react-native';
const width = Dimensions.get('window').width;
const styles = StyleSheet.create({
container: {
flexDirection: 'row',
backgroundColor: 'lightblue',
height: 200,
justifyContent: 'space-around',
},
btn: {
width: width*0.5,
backgroundColor: 'red',
padding: 20,
borderWidth: 1,
},
});

Related

I can't style properly on react-native

I'm trying to change the background color and align the items on the center, so I tried this:
<View style={Stylesheet.container}>
<TouchableOpacity style={Stylesheet.button} onPress={() => navigation.navigate("Register")}>
Register
</TouchableOpacity>
<TouchableOpacity style={Stylesheet.button} onPress={() => navigation.navigate("Login")}>
Login
</TouchableOpacity>
</View>
The file with the styles is correct, I know that because it works on the TouchableOpacity and it is here:
import { StyleSheet } from 'react-native'
const Stylesheet = StyleSheet.create({
container: {
color: '#141414',
backgroundColor: '#141414',
alignItems: 'center',
justifyContent: 'center',
height: '100vh',
display: 'flex'
},
button: {
fontSize: '20px',
backgoundColor: 'white',
color: '#f63364',
alignItems: 'center',
justifyContent: 'center',
padding: '20px'
}
})
export default Stylesheet
But when I add the styling inline, it works fine
(...)
<View style={Stylesheet.container, { flex: 1, alignItems: 'center', justifyContent: 'center', backgroundColor: '#141414'}}>
(...)
How is that possible?
Give container flex value of 1:
const Stylesheet = StyleSheet.create({
container: {
flex:1,
color: '#141414',
backgroundColor: '#141414',
alignItems: 'center',
justifyContent: 'center',
height: '100vh',
},
button: {
fontSize: '20px',
backgoundColor: 'white',
color: '#f63364',
alignItems: 'center',
justifyContent: 'center',
padding: '20px'
}
})

How can I change styles of an array element in react native

I leave a small code of sample of as I have my code, in fact my code I show it inside a FlatList... but here I leave him something similar in .map that is practically the same thing, they are dynamic Views, I wish that on having clicked in the button, that View change Styles (Position Abosulte, Width, Backgorund color and more)
import { Text, View, StyleSheet, TouchableOpacity } from 'react-native';
import Constants from 'expo-constants';
import AssetExample from './components/AssetExample';
let shopping = ['bread', 'milk', 'cheese', 'hummus', 'noodles'];
export default function App() {
return (
<View style={styles.container}>
{shopping.map((data, idx) => {
return (
<View
style={{
width: '100%',
height: 70,
backgroundColor: '#f7f7f7',
marginTop: 5,
marginBottom: 5,
borderColor: '#dfdfdf',
borderWidth: 1,
alignItems: 'center',
}}>
<Text>Tex: {data}</Text>
//I press this buttom, i want change this View Styles!!!, only this view
<TouchableOpacity onPress={() => {}}>
<View
style={{
width: '100%',
height: 30,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#f7f7f7',
marginTop: 5,
marginBottom: 5,
borderColor: '#dfdfdf',
borderWidth: 1,
borderRadius: 15,
}}>
<Text style={{ width: '100%' }}>Change</Text>
</View>
</TouchableOpacity>
</View>
);
})}
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
},
});
You can have a state variable and then set it to change the style.
<TouchableOpacity onPress={() => this.setState({changeStyleIndex:index})}>
<View
style={this.state.changeStyleIndex != index{
width: '100%',
height: 30,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#f7f7f7',
marginTop: 5,
marginBottom: 5,
borderColor: '#dfdfdf',
borderWidth: 1,
borderRadius: 15,
}:{change style goes here}}>
<Text style={{ width: '100%' }}>Change</Text>
</View>
</TouchableOpacity>
import React from 'react'
import { Text, View, StyleSheet, TouchableOpacity } from 'react-native';
import Constants from 'expo-constants';
let shopping = ['bread', 'milk', 'cheese', 'hummus', 'noodles'];
export default class App extends React.Component {
constructor(props) {
super(props)
this.state = {
BackColor = '#f7f7f7',
StateWidth: '100%'
}
}
HandleChange = () => {
this.setState({
BackColor: 'red',
StateWidth: '50%'
})
}
render() {
const { BackColor, StateWidth } = this.state
return (
<View style={styles.container}>
{shopping.map((data, idx) => {
return (
<View
style={{
width: { StateWidth },
height: 70,
backgroundColor: { BackColor },
marginTop: 5,
marginBottom: 5,
borderColor: '#dfdfdf',
borderWidth: 1,
alignItems: 'center',
}}>
<Text>Tex: {data}</Text>
//I press this buttom, i want change this View Styles!!!, only this view
<TouchableOpacity onPress={() => { this.HandleChange }}>
<View
style={{
width: '100%',
height: 30,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#f7f7f7',
marginTop: 5,
marginBottom: 5,
borderColor: '#dfdfdf',
borderWidth: 1,
borderRadius: 15,
}}>
<Text style={{ width: '100%' }}>Change</Text>
</View>
</TouchableOpacity>
</View>
);
})}
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
},
I used the component by class, but change it to function and it will give crt, the logic is basically this.

Why does changing my margin percentage mess with the spacing of my custom buttons?

I'm new to React-Native and web development, but I do have a smidge of CSS experience. I've come across an issue that I can't figure out and I haven't found anything online that expresses a similar problem so that I may figure out why this is happening.
I have custom hexagonal buttons that I want to space out in a similar fashion to an onscreen keyboard which I have done, but my buttons are a bit too far up. The first row is obscured by the notification bar. My StyleSheet for my rows look like this:
const style = StyleSheet.create({
screen: {
width: '100%',
height: '100%',
backgroundColor: '#lele19'
},
firstRow: {
alignItems: 'center',
justifyContent: 'space-between',
flexDirection: 'row',
paddingTop: '5%',
marginHorizontal: '5%'
}
row: {
alignItems: 'center',
justifyContent: 'space-between',
flexDirection: 'row',
marginHorizontal: '5%'
}
});
Each "row" of buttons is within a View component.
So to try to fix the position so that the notification bar was not in the way I changed my paddingTop: from 5% to 15% and as a result, it seems to move my row down as I want, but now the space between my buttons is increased as seen from this screenshot:
It seems that any padding I do that is past 5% causes the spacing of my buttons to be off. How can I prevent this? What am I doing wrong? It appears this way on any device whether it is a phone or a tablet. Any help is greatly appreciated.
EDIT:
Since people are asking for more here is my PortraitLayout.js:
import React from 'react';
import { View, StyleSheet } from 'react-native';
import HexButton from './HexagonButton';
const PortraitLayout = props => {
return (
<View style={styles.screen}>
<View style={styles.firstRow}>
<HexButton>a</HexButton>
<HexButton>b</HexButton>
<HexButton>c</HexButton>
<HexButton>d</HexButton>
<HexButton>e</HexButton>
<HexButton>f</HexButton>
<HexButton>g</HexButton>
<HexButton>h</HexButton>
<HexButton>i</HexButton>
</View>
<View style={styles.row}>
<HexButton>j</HexButton>
<HexButton>k</HexButton>
<HexButton>l</HexButton>
<HexButton>m</HexButton>
<HexButton>n</HexButton>
<HexButton>o</HexButton>
<HexButton>p</HexButton>
<HexButton>q</HexButton>
<HexButton>r</HexButton>
</View>
<View style={styles.row}>
<HexButton>s</HexButton>
<HexButton>t</HexButton>
<HexButton>u</HexButton>
<HexButton>v</HexButton>
<HexButton>w</HexButton>
<HexButton>x</HexButton>
<HexButton>y</HexButton>
<HexButton>z</HexButton>
</View>
</View>
);
};
const styles = StyleSheet.create({
screen: {
width: '100%',
height: '100%',
backgroundColor: '#1e1e19'
},
firstRow: {
alignItems: 'center',
justifyContent: 'space-between',
flexDirection: 'row',
paddingTop: '5%',
marginHorizontal: '5%'
},
row: {
alignItems: 'center',
justifyContent: 'space-between',
flexDirection: 'row',
paddingTop: '5%',
marginHorizontal: '5%'
}
});
export default PortraitLayout;
HexagonButton.js:
import React from 'react';
import { View, StyleSheet, TouchableOpacity, Text, Dimensions } from 'react-native';
const HexagonButton = props => {
return (
<TouchableOpacity>
<View style={styles.hexagon}>
<View style={styles.hexagonInner}>
<Text style={styles.buttonText}>{props.children}</Text>
</View>
<View style={styles.hexagonBefore} />
<View style={styles.hexagonAfter} />
</View>
</TouchableOpacity>
);
};
let buttonWidth = Dimensions.get('window').width / 11; //Make enough room for 16 even though I am only putting 13 per row.
let buttonHeight = buttonWidth * 0.55;
const styles = StyleSheet.create({
hexagon: {
width: buttonWidth,
height: buttonHeight
},
hexagonInner: {
width: '100%',
height: '100%',
backgroundColor: '#ffec33',
justifyContent: 'center',
alignItems: 'center'
},
hexagonAfter: {
position: 'absolute',
bottom: -1 * (buttonHeight * 0.45),
left: 0,
width: 0,
height: 0,
borderStyle: 'solid',
borderLeftWidth: buttonWidth * 0.5,
borderLeftColor: 'transparent',
borderRightWidth: buttonWidth * 0.5,
borderRightColor: 'transparent',
borderTopWidth: buttonHeight * 0.45,
borderTopColor: '#ffec33'
},
hexagonBefore: {
position: 'absolute',
top: -1 * (buttonHeight * 0.45),
left: 0,
width: 0,
height: 0,
borderStyle: 'solid',
borderLeftWidth: buttonWidth * 0.5,
borderLeftColor: 'transparent',
borderRightWidth: buttonWidth * 0.5,
borderRightColor: 'transparent',
borderBottomWidth: buttonHeight * 0.45,
borderBottomColor: '#ffec23'
},
buttonText: {
fontSize: 18
}
});
export default HexagonButton;
and App.js:
import React from 'react';
import { StyleSheet, View } from 'react-native';
import LandscapeLayout from './components/LandscapeLayout';
import PortraitLayout from './components/PortraitLayout';
export default function App() {
return (
<PortraitLayout/>
);
}
const styles = StyleSheet.create({
});
That is literally all of the code I have. I hope this will paint a better picture of the issue. I will try the borders thing and see what that yields.
EDIT:
Here is the result of the border color test. It looks like my buttons extend past the border. For simplicity, I only changed the top row so that the buttons were spaced incorrectly. Also for the sake of testing I added another style to the Portrait.js file that is just a copy of row.
I'm still not sure why it happens but I did manage to fix it. It had something to do with justifyContent and the fact that my button rows were not within a new of their own. I added a view around my button rows like this:
<View style={styles.screen}>
<View style={styles.keyboardLayout}>
<View style={styles.row}>
<HexButton>a</HexButton>
<HexButton>b</HexButton>
<HexButton>c</HexButton>
<HexButton>d</HexButton>
<HexButton>e</HexButton>
<HexButton>f</HexButton>
<HexButton>g</HexButton>
<HexButton>h</HexButton>
<HexButton>i</HexButton>
</View>
<View style={styles.row}>
<HexButton>j</HexButton>
<HexButton>k</HexButton>
<HexButton>l</HexButton>
<HexButton>m</HexButton>
<HexButton>n</HexButton>
<HexButton>o</HexButton>
<HexButton>p</HexButton>
<HexButton>q</HexButton>
<HexButton>r</HexButton>
</View>
<View style={styles.row}>
<HexButton>s</HexButton>
<HexButton>t</HexButton>
<HexButton>u</HexButton>
<HexButton>v</HexButton>
<HexButton>w</HexButton>
<HexButton>x</HexButton>
<HexButton>y</HexButton>
<HexButton>z</HexButton>
</View>
</View>
</View>
const styles = StyleSheet.create({
screen: {
width: '100%',
height: '100%',
backgroundColor: '#1e1e19'
},
row: {
justifyContent: 'space-between',
flexDirection: 'row',
paddingTop: '5%',
marginHorizontal: '5%'
},
keyboardLayout: {
height: '50%',
width: '100%',
alignItems: 'center',
justifyContent: 'flex-end'
}
});
I would still like to know the exact cause, but for now, my problem has been solved.

Touchable Opacity breaks centering

I am trying to style a NavBar for an app with a logo in the center and the back button on the left. I gotten pretty far in centering the logo and button horizontally. However, when I set a align-items:'center' attribute, it seems to break with Touchable Opacity. Is there a way I can center my components vertically and horizontally?
ex. |<- LOGO |
import React,{ Component } from 'react';
import { StyleSheet, View, Image, Text } from 'react-native';
import { colors } from '../../utils/theme';
import { widthScale, heightScale } from '../../utils/responsive';
import {TouchableOpacity}from 'react-native';
const logo = require('../../assets/images/logo.png');
const prev = require('../../assets/images/baseline-arrow_back-24px.png');
class NavBar extends Component{
constructor(props) {
super(props);
}
render(){
return(
<View style ={styles.nav}
<TouchableOpacity style= {styles.prev} onPress={handleClick()}>
<Image source={prev} />
</TouchableOpacity>
<Image style={styles.logo} source={logo} />
<Image source={prev} style={styles.tex} />
</View>
);
}
}
export default NavBar;
const styles = StyleSheet.create({
nav: {
flexDirection: 'row',
justifyContent: 'space-between',
backgroundColor: colors.tertiary,
width: widthScale('100%'),
height: heightScale('2%'),
paddingVertical: heightScale('4%'),
borderBottomWidth: 2,
borderWidth: 1,
flexWrap : 'wrap',
borderColor: 'green',
flex:1
},
logo: {
justifyContent: 'center',
alignItems:'center',
borderWidth: 1,
borderColor: 'blue'
},
info: {
justifyContent: 'center',
},
prev:{
borderRadius: 10,
borderWidth: 1,
borderColor: 'red',
alignItems:'center',
},
tex:{
borderRadius: 10,
borderWidth: 1,
borderColor: 'orange',
justifyContent: 'space-between',
alignItems:'center',
opacity: 0,
}
});
1. Without Touchable Buttons align-items: center, justify-content: center
2. With Touchable Buttons just justify-content: space-between
3. With Touchable Buttons justify-content: space-between and align-items: center
enter code here<SafeAreaView style={styles.maincontent}>
<View style={styles.toolbar}>
<TouchableOpacity style={{ justifyContent: 'center', }} activeOpacity={0.4} onPress={() => Actions.pop()}>
<Image source={{ uri: 'ic_arrow_back_gris_24dp' }} style={styles.back_img} />
</TouchableOpacity>
<Image source={{uri : 'logo'}} style={styles.back_txt}
/>
</View>
</SafeAreaView>
style :
maincontent: {
height: '100%',
width: '100%',
flexDirection: 'column',
backgroundColor: '#f1f1f1',
padding: 10
},
toolbar: {
backgroundColor: '#FFFFFF',
height: 50,
width: '100%',
flexDirection: 'row',
borderRadius: 3,
marginBottom: 10
},
back_img: {
height: 24,
width: 24,
justifyContent: 'center',
alignSelf: 'center',
marginLeft: 10,
padding: 4
},
back_txt: {
color: '#808080',
justifyContent: 'center',
alignSelf: 'center',
marginLeft: '13%',
fontSize: 14,
width: '65%'
},
It seems like the Touchable Opacity was stretching to fill space. By wrapping the Touchable Opacity in a View and limiting the width of that view, the styling worked as intended.
<View style={styles.nav}>
<View style={styles.toolbar}>
<TouchableOpacity style={{ justifyContent: 'nav'}} activeOpacity={0.4} onPress={this.props.prev}>
<Image source={prev} style={styles.back_img} />
</TouchableOpacity>
</View>
<Image source={logo} style={styles.back_txt}
/>
<Image source={prev} style={styles.tex} />
</View>
styles:
const styles = StyleSheet.create({
nav: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems:'center',
backgroundColor: colors.tertiary,
width: widthScale('100%'),
height: heightScale('2%'),
paddingVertical: heightScale('4%'),
borderBottomWidth: 2,
flexWrap : 'wrap',
},
tex:{
justifyContent: 'center',
alignItems:'center',
opacity: 0,
width: widthScale('10%')
},
toolbar: {
flexDirection: 'row',
alignItems: 'center',
width: widthScale('10%')
},
back_img: {
justifyContent: 'center',
alignSelf: 'center',
aspectRatio:1.5,
},
back_txt: {
justifyContent: 'center',
alignSelf: 'center',
},
});

Image shadow not showing up using React Native on iOS

I've been trying to add a shadow to an image and display it on an iOS device, but it just not showing up.
Any idea what I'm missing?
Here's the JSX:
<View style={styles.container}>
<Image style={styles.pic} source={pic} />
</View>
And the styles:
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'white',
},
pic: {
width: 200,
height: 200,
shadowOffset: { width: 10, height: 10 },
shadowColor: 'black',
shadowOpacity: 1,
backgroundColor: '#0000',
},
});
You can view the live demo here.
According to React-native documentation : https://facebook.github.io/react-native/docs/image-style-props
There is no shadow possibilities for an Image style, thus you need to wrap it in a View and add a shadow to this view :
<View style={styles.mainContainer}>
<View style={styles.imageContainer}>
<Image style={styles.pic} source={pic} />
</View>
</View>
And style it like this :
const styles = StyleSheet.create({
mainContainer: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'white',
},
imageContainer: {
shadowOffset: { width: 10, height: 10 },
shadowColor: 'black',
shadowOpacity: 1,
backgroundColor: '#0000',
},
pic: {
width: 150,
height: 150,
},
});