I'm working in react native and I'm trying to style a component. I have a view (black border) that wraps two views (A and B). I would like something that looks like this - where I the view that wraps A has a width of about 75% and the view that wraps B has a width of about 25%.
When this component is rendered out as a list, however, what I'm getting is something like this - where the width of the A view is dependent on how much text it holds.
I was able to set the width to a specific amount, but it always seems to change based on the device I test it on (different on iPhone 5, 6, 6 plus, etc.). Therefore I'm trying to use flex styling, but can't seem to get it right. Here is my code for my styling and component structure:
const styles = StyleSheet.create({
title: {
color: '#000',
textAlign: 'left',
fontSize: 80,
},
row: {
flex: 1,
flexDirection: 'row',
padding: 0,
height: 180,
borderBottomColor: '#888',
borderBottomWidth: 1,
alignItems: 'stretch'
},
innerContainer: {
flex: 1,
padding: 0,
flexDirection: 'row',
alignItems: 'stretch',
},
sideDivider: {
flex: 0.8,
padding: 0,
backgroundColor: '#cacaca',
justifyContent: 'center'
},
sideDividerArrow: {
flex: 0.2,
padding: 0,
alignItems: 'center',
backgroundColor: 'cyan',
justifyContent: 'center',
},
});
...
render() {
return (
<View style={styles.row} ref={component => this._root = component}>
<TouchableHighlight onPress={this.handleClick.bind(this)}>
<View style={styles.innerContainer}>
<View style={styles.sideDivider}>
<Text style={styles.title}>
{this.state.routeData.busNumber}
</Text>
<Text>{this.state.routeData.fullRoute}</Text>
</View>
<View style={styles.sideDividerArrow}>
<Text>></Text>
</View>
</View>
</TouchableHighlight>
</View>
)
}
}
Any and all help is appreciated. Thanks!!
The flex attribute expects an integer. We cannot use fractions for it.
I guess rendering the following will help you achieve the desired look. You can then add your interactions and clean up the inline styles
<View style ={{flexDirection:'row',flex:1,borderColor:'black',borderWidth:1}}>
<View style ={{flex:3,backgroundColor:'blue',alignItems:'center',justifyContent:'center'}}>
<Text>A</Text>
</View>
<View style ={{flex:1,backgroundColor:'yellow',alignItems:'center',justifyContent:'center'}}>
<Text>B</Text>
</View>
</View>
Your picture has 3 components, but the code actually has more.
The code should work as intended if you do:
- row: flex: 1 (to make sure row is full width) + flexDirection: 'row' (so row children will be left to right).
- A container: flex: 3.
- B container: flex: 1.
At least one of the children of A or B should have a flex: 1 (or any other number) to ensure that children also stretch to fill the parent.
In your case, giving the title and the text components a flex: 1 property will probably do the trick.
Hope this helps!
Related
I am building an app using react-navigation. I replaced the default header with my own custom component
const CustomHeader = () => {
return (
<View style={styles.header}>
<Text style={{color: 'white'}}>Welcome Stranger!</Text>
<Image
style={{ width: 50, height: 50 }}
source={require("./assets/logo.png")}
/>
</View>
);
}
styles.header (where deviceWidth = Dimensions.get("window").width):
header: {
flex: 1,
flexDirection: "row",
justifyContent: 'flex-start',
alignItems: "center",
width: deviceWidth,
borderBottomColor: colors.primary,
borderBottomWidth: 2
}
However my header component is not aligned right. There is a gap on the left and it overflows on the right. Why is this happening?
Check the styling of the parent component once it may be coming from the parent component.
also, you can inspect the style using the developers option
I'm having a terrible time with layout in one spot. I'd like the View with the buttons to get a consistent amount of space, and then the rest of the space goes to the box with ingredient names on the left.
Here's a screenshot, using Expo Go on iPhone.
Screenshot with problem layout.
I wanted the left box (nameView, red outline) to take all the space not needed by the buttons, but I'm failing miserably. The top row is too small, the second row is too wide and is pushing the buttons off the screen!
Here's the (slightly simplified) return:
<View style={styles.rowView} key={oneitem\[0\]}>
<TouchableOpacity >
<View style={\[styles.nameView, { backgroundColor: oneitem\[1\].sku?'white': 'red'}\]}>
<Text style={styles.itemtext}>{oneitem\[0\]}</Text> <Text>{oneitem\[1\].sku}</Text>
</View>
</TouchableOpacity>
<View style={styles.buttonView}>
<Button style={styles.smallButton} >
<Image source={Images.trash} style={styles.trashButton}/></Button>
<Button style={styles.smallButton} ><Text style={styles.smallbuttonText}>-</Text></Button>
<Text style={styles.quantitytext}>{oneitem\[1\].quantity}</Text>
<Button style={styles.smallButton} > <Text style={styles.smallbuttonText}>+</Text></Button>
</View>
</View>
And here's the relevant styling:
rowView: {
marginBottom: 4,
flexDirection: 'row',
borderWidth: 2,
borderColor: 'yellow',
width: '100%',
maxWidth: '100%',
flex: 1 ,
justifyContent: 'space-between'
},
nameView: {
flex: 1,
flexDirection: 'column',
alignSelf: 'center',
marginLeft: 4,
borderWidth: 1,
borderColor: 'red',
flexGrow: 2,
},
buttonView: {
flexDirection: 'row',
alignContent: 'space-around',
alignItems: 'center',
borderWidth: 1,
width: 125,
flexShrink: 125,
},
UPDATE: I found my issue. I needed to apply the nameView styling to the TouchableOpacity. Next problem: how to get the rows to expand vertically when the text wraps.
Second attempt
The left view should have flex: 1 style! and the left view should have fix width
I found my issue - I needed to apply the nameView style to the TouchableOpacity also. That gets the text to wrap, although now the rows are too short.
Trying to implement a thingy with no luck. Any help would be highly appreciated.
As much elements as possible should be displayed per row, but only if they fit. Elements might be with different width ( depending on a text ). Everything should be centered.
A picture is worth a thousands words:
Tried lots of things nothing worked..
Thanks in advance.
These are two useful links in your case https://facebook.github.io/react-native/docs/flexbox.html and https://facebook.github.io/react-native/docs/layout-props.html#flexwrap
That code works for me successfully on iOS
export default class App extends Component {
render() {
return (
<View style={styles.container}>
<TouchableHighlight style={styles.button}><Text style={styles.buttonText}>Hello</Text></TouchableHighlight>
<TouchableHighlight style={styles.button}><Text style={styles.buttonText}>Some app</Text></TouchableHighlight>
<TouchableHighlight style={styles.button}><Text style={styles.buttonText}>TV&Internet</Text></TouchableHighlight>
<TouchableHighlight style={styles.button}><Text style={styles.buttonText}>Remarkable</Text></TouchableHighlight>
<TouchableHighlight style={styles.button}><Text style={styles.buttonText}>It works</Text></TouchableHighlight>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
paddingTop: 60,
alignItems: 'center',
justifyContent: 'center',
flex: 1,
flexDirection: 'row',
flexWrap: 'wrap'
},
button: {
marginBottom: 30,
width: 'auto',
marginLeft: 10,
alignItems: 'center',
backgroundColor: '#2196F3'
},
buttonText: {
padding: 20,
color: 'white'
}
});
Here is my code. I want the product view to take up 90% width of its parent. However, the settings below are not working.
...any idea how to achieve it without using dimensions?
return (
<LazyloadScrollView
style={styles.container}
contentContainerStyle={styles.content}
name="scrollImage" >
{list.map((product, i) => <View key={i} style={styles.product}>
<LazyloadImage
host="scrollImage"
style={styles.image}
source={image}
animation={false}>
<View style={styles.id}>
<Text style={styles.idText}>{product.id}</Text>
</View>
</LazyloadImage>
</View>)
}
</LazyloadScrollView>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#ffffff'
},
content: {
paddingTop: 20,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#eee'
},
product: {
flex: 0.9,
marginTop: 5,
flexDirection: 'row',
alignItems: 'center',
backgroundColor: '#FFFFFF'
},
Why not use Dimensions? It will enable your app to be responsive.
If you don't want to use dimensions, try some style settings in the container and it's children, for example, make it full width with padding
container: {
backgroundColor: '#ffffff',
alignSelf: 'stretch',
padding: 30
}
I don't know if it works because you would have to post the rest of the code to test it but keep playing with the style and flex properties until you make it work, shouldn't take long.
Btw, always good to revisit the official layout props docs from react native
And css tricks guide to flexbox
In react native I have:
<View style={styles.navBar}>
<Text>{'<'}</Text>
<Text style={styles.navBarTitle}>
Fitness & Nutrition Tracking
</Text>
<Image source={icon} style={styles.icon}/>
</View>
with these styles:
{
navBar: {
height: 60,
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
},
navBarTitle: {
textAlign: 'center',
},
icon: {
height: 60,
resizeMode: 'contain',
},
}
This is the effect I get:
This is the effect I want:
In the first example, the spacing between items is equal.
In the second example, each item is justified differently. The first item is left-justified. The second item is center-justified. The third, right-justified.
This question is similar, but it looks like react native does not support margin: 'auto'. Furthermore, the other answers only work if you only care about left and right justification, but no one really addresses center justification without auto margin.
I am trying to make a navigation bar in react native. The vanilla ios version looks like this:
(source: apple.com)
How do I do something similar? I'm mainly concerned with centering.
One way is to use nested View (flex containers) for 3 different regions and set flex:1 to left and right region
<View style={styles.navBar}>
<View style={styles.leftContainer}>
<Text style={[styles.text, {textAlign: 'left'}]}>
{'<'}
</Text>
</View>
<Text style={styles.text}>
Fitness & Nutrition Tracking
</Text>
<View style={styles.rightContainer}>
<View style={styles.rightIcon}/>
</View>
</View>
const styles = StyleSheet.create({
navBar: {
height: 60,
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
backgroundColor: 'blue',
},
leftContainer: {
flex: 1,
flexDirection: 'row',
justifyContent: 'flex-start',
backgroundColor: 'green'
},
rightContainer: {
flex: 1,
flexDirection: 'row',
justifyContent: 'flex-end',
alignItems: 'center',
backgroundColor: 'red',
},
rightIcon: {
height: 10,
width: 10,
resizeMode: 'contain',
backgroundColor: 'white',
}
});
You could also set marginLeft: 'auto' to the middle component. It should push it to the right. Also works for React Native
Source: https://hackernoon.com/flexbox-s-best-kept-secret-bd3d892826b6
If you're using a NavigationBar from the Navigator module see my question: Changing the default style for a Navigator.NavigationBar (title)
use this
marginLeft: "auto",
marginRight: "auto"