I am trying to arrange 4 flex items in a flex row, the items have dynamic content, so the width can not be specified for the flex item.
is there any way for the flex items reduce their font size dynamically and occupy the full width of the container??
I was trying this in a sandbox and below code is cutting off the 4th row when the contents are not able to fit.
App Component:
function App() {
const a = [12, 1234, 123456, 123456789];
return (
<View style={styles.app}>
{a.map((element) => {
return (
<View style={styles.item}>
<Text style={[styles.text, { fontSize: 24 }]}>{element}</Text>
</View>
);
})}
</View>
);
}
Styles:
const styles = StyleSheet.create({
app: {
display: "flex",
backgroundColor: "black",
width: "100%",
height: "20%",
flexDirection: "row"
},
text: {
color: "white"
},
item: {
flexGrow: 0,
flexShrink: 0,
minWidth: "15%",
borderStartWidth: 1,
borderColor: "white",
justifyContent: "center",
padding: 5,
alignItems: "flex-start"
}
});
Screenshot:
You've set
flexGrow: 0,
flexShrink: 0,
This explicitly prevents the behaviour you're asking for. Removing both will default them to 1 and allow it to respond to available space.
I have written following code but my flex under 'titleContainer' is not working.
export const Focus = () => {
return (
<View style={styles.container}>
<View style={styles.titleContainer}>
<Text style={styles.title}>What would you like to focus on?</Text>
<TextInput />
</View>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#43840',
},
titleContainer: {
flex: 0.5,
padding: 16,
justifyContent: 'center',
backgroundColor: '#559974',
},
title: {
color: 'white',
fontWeight: 'bold',
fontSize: 15,
},
});
Please see the screen shot. The green background should cover half of the screen.
Its resolved now!
Actually this component was getting displayed conditionally. There was an issue with that condition. I have fixed that and everything worked.
Flex in RN only take interger value
In case you want titleContainer take 50% size of container by using flex, This is how you can achieve that.
You need another view the take the same flex value with titleContainer, so titleContainer and that dump view will take 50% size of parent view each
export const Focus = () => {
return (
<View style={styles.container}>
<View style={styles.titleContainer}>
<Text style={styles.title}>What would you like to focus on?</Text>
<TextInput />
</View>
<View style={{flex: 1}} />
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#43840',
},
titleContainer: {
flex: 1,
padding: 16,
justifyContent: 'center',
backgroundColor: '#559974',
},
title: {
color: 'white',
fontWeight: 'bold',
fontSize: 15,
},
});
To use flex property on child tag your parent tag needs to have a display: "flex" property on it.
container: {
display: 'flex',
flexDirection: 'column',
flex: 1,
backgroundColor: '#43840',
},
Having trouble getting the text and image to line up side by side in this setup:
https://snack.expo.io/XZef1XEje
Does adding width to topHomeTextContainer actually help line up the elements? I tried adding an extra <View />, but that didn't do anything.
If the link doesn't work:
import React, { useState } from "react"
import { StyleSheet, Image, Text, TouchableOpacity, View } from "react-native"
const App = () => {
return (
<View stye={styles.topHomeContainer}>
<View style={styles.topHomeTextContainer}>
<Text style={styles.topHomeText}>Find Things</Text>
</View>
{/* <View style={styles.topHomeImageContainer}> */}
<TouchableOpacity
style={styles.topHomeImage}
>
<Image
style={styles.arrowIcon}
source={{uri:"https://i.pinimg.com/originals/4d/4d/b9/4d4db9216358ec06d74d20507ed75c49.png"}}
/>
</TouchableOpacity>
{/* </View> */}
</View>
)
}
const styles = StyleSheet.create({
topHomeContainer: {
flex: 1,
flexDirection: `row`,
alignItems: `stretch`,
justifyContent: `center`,
height: 100,
marginBottom: 15,
},
topHomeTextContainer: {
//width: `65%`,
},
topHomeText: {
color: `rgb(0,0,0)`,
fontFamily: "GothamMedium",
fontSize: 20,
fontWeight: `500`,
letterSpacing: 0,
},
// topHomeImageContainer: {
// width: scaleHelper.w(32),
// },
//topHomeImage: { width: 32 },
arrowIcon: {
width: 32,
height: 32
},
})
export default App
UPDATE 1: added width and height to image.
You should give width and height style to Image style - arrowIcon. Also no need to give width to topHomeImage style.
// topHomeImage: {
// width: 32
// },
arrowIcon: {
width: 32,
height: 32
},
Update
Also, I found a typo stye on your code.
Change
<View stye={styles.topHomeContainer}>
to
<View style={styles.topHomeContainer}>
I am displaying a FlatList with variable number of items and the last item always is not visible completely (border bottom).
render()
render() {
return (
<View style={styles.container}>
<FlatList style={styles.list} containContainerStyle={{paddingBottom: 20}}
...
/>
</View>
);
}
CSS
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'white'
},
list: {
flex: 1,
width: "95%"
}
You are using a wrong style property for the flat list, it is contentContainerStyle not containContainerStyle. You will have to increase it according to the size of your item.
<FlatList contentContainerStyle={{ paddingBottom: 20}} />
Suppose this is the layout:
<View style={styles.container}>
<View style={styles.titleWrapper}>
...
...
</View>
<View style={styles.inputWrapper}>
...
...
</View>
<View style={styles.footer}>
<TouchableOpacity>
<View style={styles.nextBtn}>
<Text style={styles.nextBtnText}>Next</Text>
</View>
</TouchableOpacity>
</View>
</View>
I want to make the view with the styles of footer to position at the bottom of the screen. I tried giving the alignSelf property to the footer, but instead of positioning at the bottom, it positions it to the right side of the screen. How can I make the footer item stick to the end? Thank you.
I would use the following approach:
<View style={styles.container}>
<View style={styles.contentContainer}> {/* <- Add this */}
<View style={styles.titleWrapper}>
...
</View>
<View style={styles.inputWrapper}>
...
</View>
</View>
<View style={styles.footer}>
...
</View>
</View>
var styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#F5FCFF',
},
titleWrapper: {
},
inputWrapper: {
},
contentContainer: {
flex: 1 // pushes the footer to the end of the screen
},
footer: {
height: 100
}
});
This way the styles of titleWrapper and inputWrapper can be updated without breaking the layout of your app and the components themselves are easier to re-use :)
In React Native, the default value of flexDirection is column (unlike in CSS, where it is row).
Hence, in flexDirection: 'column' the cross-axis is horizontal and alignSelf works left/right.
To pin your footer to the bottom, apply justifyContent: 'space-between' to the container
for me the answer was to create a container view for the elements, then for the style.
bottomContainer: {
flex: 1,
justifyContent: 'flex-end',
}
Absolutely position is another way to fix footer, just like:
footer: {
position: 'absolute',
height: 40,
left: 0,
top: WINDOW_HEIGHT - 40,
width: WINDOW_WIDTH,
}
To fix a View to the bottom, simply use: marginTop: 'auto' .
This worked for me after searching like an hour on the net. I tried experimenting and it worked!
Consider a screen structure
<View style={styles.container}>
<View style={styles.body}> ... </View>
<View style={styles.footer}>...</View>
</View>
You can do it cleanly using Flexbox approach utilizing flex-grow.
const Styles = StyleSheet.create({
container:{
flexDirection: 'column', // inner items will be added vertically
flexGrow: 1, // all the available vertical space will be occupied by it
justifyContent: 'space-between' // will create the gutter between body and footer
},
})
Note: In case of nested elements, you have to ensure that the parent container has enough height to work with when using flexGrow. Set backgroundColor on parents and child to debug.
To do this you can use the Stylesheet element position: 'absolute'.
/*This is an Example to Align a View at the Bottom of Screen in React Native */
import React, { Component } from 'react';
import { StyleSheet, View, Text } from 'react-native';
export default class App extends Component {
render() {
return (
<View style={styles.containerMain}>
<Text> Main Content Here</Text>
<View style={styles.bottomView}>
<Text style={styles.textStyle}>Bottom View</Text>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
containerMain: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
bottomView: {
width: '100%',
height: 50,
backgroundColor: '#EE5407',
justifyContent: 'center',
alignItems: 'center',
position: 'absolute', //Here is the trick
bottom: 0, //Here is the trick
},
textStyle: {
color: '#fff',
fontSize: 18,
},
});
You can use this style:
row: {
flexDirection: 'row',
height: 50,
justifyContent: 'center',
alignItems: 'center',
position: 'absolute', //Here is the trick
bottom: 0,
}
embed other content in a scrollview
<View style={styles.container}>
<ScrollView> {/* <- Add this */}
<View style={styles.titleWrapper}>
...
</View>
<View style={styles.inputWrapper}>
...
</View>
</ScrollView>
<View style={styles.footer}>
...
</View>
</View>
In react native, there are some properties like position: 'absolute', bottom: 0, which you will want to give to your button view
Quick example in essence, based on #David's answer:
<View style={{flex: 1}}>
<View style={{flex: 1}}>
<Text>Main content</Text>
</View>
<Text>Footer</Text>
</View>
import React from 'react'
import { View, StyleSheet } from 'react-native'
function moveToBottom(component) {
return (
<View style={styles.container}>
{component}
</View>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'flex-end',
marginBottom: 36
}
})
export default moveToBottom
Now in our screen, we just need to import:
import moveToBottom from 'library/utils/moveToBottom'
and wrap our button:
{
moveToBottom(
<ImageButton
style={styles.button}
title={strings.onboarding.welcome.button}
onPress={() => {
this.props.navigation.navigate('Term')
}} />
)
}
I tested it and I approve it's the best option to respect the layout without having fixed things to bottom, which is not possible if you use react-native-web in addition of react-native, because people resize and elements overlap on each over.
Source: https://medium.com/react-native-training/position-element-at-the-bottom-of-the-screen-using-flexbox-in-react-native-a00b3790ca42
I have a case in which I have to show a image in the bottom like this, as you can see the sky-blue image is not poped-up with keyboard.
so for this I have created a functional component for image in bottom.
import React, { useEffect, useState } from "react";
import { Keyboard, View, Image } from "react-native";
export const BottomImage = (props) => {
const [shouldShow, showImage] = useState(true);
useEffect(() => {
Keyboard.addListener("keyboardDidShow", _keyboardDidShow);
Keyboard.addListener("keyboardDidHide", _keyboardDidHide);
return () => {
Keyboard.removeListener("keyboardDidShow", _keyboardDidShow);
Keyboard.removeListener("keyboardDidHide", _keyboardDidHide);
};
}, []);
let _keyboardDidShow = () => {
showImage(false)
}
let _keyboardDidHide = () => {
showImage(true)
}
return (<ViewToRender show={shouldShow} src={props.image} />)
}
function ViewToRender(props) {
return props.show ? <Image style={{ position: 'absolute', bottom: 0 }} source={props.src} /> : <View />
}
and to use this Bottom image you have to pass your image to it like :
<BottomImage image={AppImage.signupbottom} />
This can be a bit tricky given that parent components can still affect the height of children with 'absolute' styles, I also tried doing "bottom: 0, height: 'auto'" like with normal HTML/CSS, but it didn't work out well, down the line I'll probably create a general component which makes sure the view can fit into the screen size. End result of view with contents
<View> component parameters
style={{
position: 'absolute',
left: 0,
padding: ContainerPadding,
top: TopOffset,
width: ScreenWidth
}}
onLayout={(event) => {
var {x, y, width, height} = event.nativeEvent.layout; // get the View's dimensions after 1st render
SetTopOffset(ScreenHeight - height - HeaderHeight); // Set 'top' to: screen size - height (of view) - parent top offset (optional if no parent offset)
}}
With useState:
const [TopOffset, SetTopOffset] = useState<number>(0); // Controls 'top' of screen
HeaderHeight is the height which is added to all my page components, you can remove this variable if you do not have any top spacing. (currently set to 64 default and this variable is updated based on device)
ScreenWidth & ScreenHeight are calculated here: export const ScreenWidth = Dimensions.get('screen').width; export const ScreenHeight = Dimensions.get('screen').height;
ContainerPadding is a general padding number used across my project (currently set to 12.5)