I'm trying to change the background color of my app, but the color doesn't fill the whole screen. When I set flex to 0, the background color only spans the needed amount, but when I set it to 1, instead of expanding the whole screen, it shrinks. What did I do wrong?
Here's the code, changing the root view flex:
render() {
return (
<Text>{welcome}</Text>
<TextInput
underlineColorAndroid="rgba(0,0,0,0)"
placeholder={email}
autoCapitalize="none"
style={styles.textInput}
onChangeText={email1 => this.setState({ email1 })}
/>
<TextInput
underlineColorAndroid="rgba(0,0,0,0)"
secureTextEntry
placeholder={password}
autoCapitalize="none"
style={styles.textInput}
onChangeText={password1 => this.setState({ password1 })}
value={this.state.password1}
/>
{this.state.errorMessage && (
<Text style={styles.error}>{this.state.errorMessage}</Text>
)}
<TouchableOpacity
onPress={this.handleSignUp}
style={styles.buttonContainer}
>
<Text style={styles.buttonText}>{signup}</Text>
</TouchableOpacity>
<Text
style={styles.text}
onPress={() => this.props.navigation.navigate("LoginScreen")}
>
{already_have_an_account}
</Text>
</KeyboardAvoidingView>
);
}
}
const styles = StyleSheet.create({
container: {
justifyContent: "center",
padding: 20,
backgroundColor: "red",
flex: 0
},
textInput: {
height: 40,
marginTop: 8,
paddingHorizontal: 8,
backgroundColor: "#e2e2e2"
},
buttonContainer: {
backgroundColor: "#3bd774",
padding: 15,
marginTop: 10
},
buttonText: {
textAlign: "center",
color: "white",
fontWeight: "bold"
},
logo: {
width: 200,
height: 200
},
logoContainer: {
alignItems: "center",
justifyContent: "center"
},
text: {
marginTop: 16,
color: "#bcbcbc",
textAlign: "center"
},
error: {
marginTop: 8,
color: "red"
}
});
You need to make sure you have flex:1 all the way down the chain of views. This is because flex: 1 will make the view fill its parent
I can see that what you have copy/pasted isn't all of the code, since there is a </KeyboardAvoidingView> but no opening tag.
So, at the very least you need a <KeyboardAvoidingView style={{flex: 1}}>, but if there is something wrapping that, you should add flex:1 to that control as well.
Put whole layout in a View wrapper and give this style to this view
container: {
justifyContent: "center",
padding: 20,
alignItems:'center',
backgroundColor: "red",
flex: 1
}
Running example: https://snack.expo.io/Hy-Gv-lGm
Related
One of my React Native screens needs to have a TouchableOpacity at the bottom of the screen. I've tried setting position: "absolute" and bottom: 0, however, this just causes the element to be a few hundred pixels below the screen. How can I make my TouchableOpacity be at the bottom of the screen all the time?
<View style={styles.mainView}>
<View style={{ position: "relative" }}>
<TouchableOpacity style={styles.cartView}>
<Text style={styles.cartText}>View cart</Text>
</ViewTouchableOpacity
</View>
}
/>
</View>
//styles
const styles = StyleSheet.create({
mainView: {
// devDims are the device dimensions
minHeight: devDims.height,
minWidth: devDims.width,
backgroundColor: "white",
paddingLeft: 10,
paddingRight: 10,
paddingTop: 10,
},
cartView: {
justifyContent: "center",
alignItems: "center",
maxHeight: 50,
minWidth: "100%",
alignSelf: "center",
marginTop: 50,
padding: 10,
borderRadius: 20,
},
cartText: {
fontFamily: "semi",
fontSize: 22,
},
});
We could handle this without absolute positioning using flex alone.
Add flex:1 to the parent view and to the view that wraps the sticky bottom. Then, add flex: 2 to the view that wraps the other content.
Here is a minimal generic component that lets you add a sticky bottom component.
const MainScreen = ({bottom, children}) => {
return <View style={{flex: 1, backgroundColor: 'red'}}>
<View style={{flex: 2, backgroundColor: 'green'}}>
{children}
</View>
<View style={{flex: 1, backgroundColor: 'yellow'}}>
{bottom}
</View>
</View>
}
export default function App() {
return <MainScreen bottom={
<TouchableOpacity style={styles.cartView}>
<Text style={styles.cartText}>View cart</Text>
</TouchableOpacity>}>
</MainScreen>
}
The result looks as follows:
However, we can use absolute positioning as well. You are just missing the flex: 1 for the parent view.
export default function App() {
return <View style={styles.mainView}>
<View style={{ position: "absolute", bottom: 0 }}>
<TouchableOpacity style={styles.cartView}>
<Text style={styles.cartText}>View cart</Text>
</TouchableOpacity>
</View>
</View>
}
const styles = StyleSheet.create({
mainView: {
flex: 1,
// devDims are the device dimensions
minHeight: devDims.height,
minWidth: devDims.width,
backgroundColor: "red",
paddingLeft: 10,
paddingRight: 10,
paddingTop: 10,
},
cartView: {
justifyContent: "center",
alignItems: "center",
maxHeight: 50,
minWidth: "100%",
backgroundColor: "yellow",
alignSelf: "center",
marginTop: 50,
padding: 10,
borderRadius: 20,
},
cartText: {
fontFamily: "semi",
fontSize: 22,
},
});
The result is as follows:
if you are using position as absolute then your view must be last view before last closed view tag
When you have declared any view at bottom of the screen then you should be do like this
import {View, SafeAreaView} from 'react-native';
<SafeAreaView style={{flex:1}}>
<View style={{flex:1}}>
<!---Anything extra views---!>
<View style={{bottom:0,position:'absolute',start:0,end:0}}> !-- you're bottom view
<TouchableOpacity style={styles.cartView}>
<Text style={styles.cartText}>View cart</Text>
</ViewTouchableOpacity
</View>
</View>
</SafeAreaView >
When adding horizontal={true} to my scrollview, I thought that would be enough to be able to scroll sideways. For some reason, even though there is enough content to scroll to, the images will not scroll continuously. If you copy and paste this code into snack.expo.io you will see what I mean.
I am not sure what is causing this issue, as I know the normal scrollview vertically works fine and scrolls like normal. I have also tried using nestedScrollenabled to true
Any insight at all is appreciated more than you know!
import React, { useState } from 'react';
import {Pressable, StyleSheet, Text, View, useWindowDimensions, Dimensions, Image, Animated, PanResponder,
TouchableOpacity, ScrollView, ImageBackground, Platform} from 'react-native';
import { SearchBar } from 'react-native-elements';
import {
scale,
verticalScale,
moderateScale,
ScaledSheet,
} from 'react-native-size-matters';
import { MaterialCommunityIcons } from '#expo/vector-icons';
const Images = [
{ id: '1', uri: require('./assets/snack-icon.png'), text: 'Test' },
{ id: '2', uri: require('./assets/snack-icon.png') /*text: "Test"*/ },
{ id: '3', uri: require('./assets/snack-icon.png') /*text: "Test"*/ },
{ id: '4', uri: require('./assets/snack-icon.png') /*text: "Test"*/ },
]
const pressableTest = () => {
let textlog = '';
const [state, setState] = useState(0);
};
export default class Home extends React.Component {
renderImagesHorizontal = () => {
return Images.map((item, i) => {
return (
<View
style={{
width : '150%',
paddingLeft: scale(10),
paddingRight: scale(10),
paddingBottom: scale(15),
}}>
<TouchableOpacity
onPress={() => this.props.navigation.navigate('VenueDetails')}>
<ImageBackground
source={item.uri}
style={{
width: '100%',
height: scale(225),
shadowColor: '#000',
shadowOffset: { width: 1, height: 4 },
shadowOpacity: 1,
}}
imageStyle={{ borderRadius: 10 }}>
<View
style={{
position: 'absolute',
bottom: 10,
left: 10,
justifyContent: 'flex-start',
alignItems: 'flex-start',
}}>
<Text style={styles.name}>Name</Text>
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
<Text style={styles.category}>Category</Text>
<Text style={styles.dot}>⬤</Text>
<Text style={styles.money}>$$</Text>
<Text style={styles.dot}>⬤</Text>
<Text style={styles.starRating}>★★★</Text>
</View>
</View>
</ImageBackground>
</TouchableOpacity>
</View>
);
});
};
renderImagesVertical = () => {
return Images.map((item, i) => {
return (
<View style={{ paddingLeft: scale(10), paddingRight: scale(10), paddingBottom: scale(20) }}>
<TouchableOpacity
onPress={() => this.props.navigation.navigate('VenueDetails')}>
<ImageBackground
source={item.uri}
style={{ width:'100%', height: scale(125),
shadowColor: '#000',
shadowOffset: {width: 1, height: 7},
shadowOpacity: 1,}} imageStyle = {{ borderRadius: 20}}>
<View
style={{
position: 'absolute',
bottom: 10,
left: 10,
justifyContent: 'flex-start',
alignItems: 'flex-start',
}}>
<Text style={styles.name}>Name</Text>
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
<Text style={styles.category}>Category</Text>
<Text style={styles.dot}>⬤</Text>
<Text style={styles.money}>$$</Text>
<Text style={styles.dot}>⬤</Text>
<Text style={styles.starRating}>★★★</Text>
</View>
</View>
</ImageBackground>
</TouchableOpacity>
</View>
);
});
};
state = {
search: '',
};
updateSearch = (search) => {
this.setState({ search });
};
render() {
const { search } = this.state;
return (
<ScrollView style={{ flex: 1, backgroundColor: '#272933', horizontal: 'true' }}>
<View style={{flexDirection:'row', marginTop: scale(20)}}>
{/*this will proabbly say somethign different and probably have a different look to it but you get the idea
I was also trying to add a shadow to this but couldnt figure it out. */}
<Text style={{marginTop: scale(30) ,fontSize: scale(40), fontWeight: 'bold', color: '#FFFFFF', paddingLeft: scale(20)}}>
Home
</Text>
<View style={{paddingTop: scale(40), paddingLeft: scale(155)}}>
</View>
</View>
<SearchBar
placeholder="Search..."
onChangeText={this.updateSearch}
value={search}
round='true'
containerStyle={{backgroundColor: '#272933', borderBottomColor: 'transparent', borderTopColor: 'transparent',
paddingLeft: scale(20) , paddingRight: scale(20)}}
inputContainerStyle={{height: scale(30), width: scale(310), backgroundColor: '#3A3B3C'}}
searchIcon={() => <MaterialCommunityIcons name="glass-mug-variant" size={25} color='#87909A'/>}
clearIcon= 'null'
/>
<ScrollView
horizontal={true}
>
<View style={{ flex: 1, flexDirection : 'row', marginTop: 15 }}>{this.renderImagesHorizontal()}</View>
</ScrollView>
<View style={{ flex: 1, marginTop: 15 }}>{this.renderImagesVertical()}</View>
</ScrollView>
);
}
}
const styles = ScaledSheet.create({
starRating: {
color: 'white',
fontSize: '20#s',
textShadowOffset: { width: 2, height: 2 },
textShadowRadius: 2,
textShadowColor: '#000',
},
category: {
color: 'white',
fontSize: '20#s',
textShadowOffset: { width: 2, height: 2 },
textShadowRadius: 2,
textShadowColor: '#000',
},
name: {
fontWeight: 'bold',
color: 'white',
fontSize: '25#s',
textShadowOffset: { width: 2, height: 2 },
textShadowRadius: 2,
textShadowColor: '#000',
},
dot: {
color: 'white',
fontSize: '5#s',
paddingLeft: '5#s',
paddingRight: '5#s',
textShadowOffset: { width: 2, height: 2 },
textShadowRadius: 2,
textShadowColor: '#000',
},
money: {
color: 'white',
fontSize: '20#s',
},
});
in android you must add nestedScrollEnabled={true} to Enables nested scrolling for Android API level 21+. see here
<ScrollView>
<ScrollView nestedScrollEnabled={true}>
</ScrollView>
</ScrollView>
try snack here (test in android & ios not web)
I am rendering an item in a list like this:
return (
<View style={styles.item}>
<View style={styles.nameAddressContainer}>
<Text style={styles.customisedName}>{place.customisedName}</Text>
<Text style={styles.address}>{place.placeName}</Text>
</View>
<View style={styles.deleteButtonContainer}>
<Button
rounded
style={styles.deleteButton}
onPress={() => onDeletePlace(place.id)}>
<Icon name="trash-o" size={moderateScale(15)} color="black" />
</Button>
</View>
</View>
);
export const styles = StyleSheet.create({
item: {
backgroundColor: '#d7fce4',
borderRadius: moderateScale(20),
marginVertical: moderateScale(8),
marginHorizontal: 16,
height: moderateScale(60),
justifyContent: 'space-between',
flexDirection: 'row',
},
customisedName: {
paddingTop: moderateScale(10),
},
deleteButton: {
backgroundColor: 'white',
width: moderateScale(35),
height: moderateScale(35),
justifyContent: 'center',
},
deleteButtonContainer: {
paddingTop: 7,
paddingRight: 7,
position: 'relative',
},
nameAddressContainer: {
flexDirection: 'column',
paddingLeft: moderateScale(10),
},
address: {
fontSize: moderateScale(9),
},
});
When the placeName text is too long, it pushes the button towards the right. The button moves out of the main green view. How can I stop this from happening? Is it possible to fix the button's position while the placeName text hides or moves to the next line?
position: fix is invalid for React Native stylesheets. I have also tried using zIndex but that didn't work either.
Add CSS for nameAddressContainer as
style = {{ flex : 1}}
Put your "deleteButtonContainer" style in "absolute" and add marginRight to your placeName equal to or slightly larger than the width of your DeleteButton.
Something like that:
...,
deleteButtonContainer: {
right: 8,
top: 8,
position: 'absolute',
},
...,
address: {
fontSize: moderateScale(9),
marginRight: moderateScale(38)
},
I have a list that shows results matching the user's input. The onPress of the touchableOpacity is not working in this list. This list is positioned absolutely and positioned below its parent view (positioned relative). The only time I can get the onPress to work is when I remove the top:48 style from list and the onPress works for the single element which is directly onTop of the parent.
export default function IndoorForm(props) {
return (
<View style={styles.container}>
<View style={styles.parent}>
<Autocomplete
style={styles.autocomplete}
autoCompleteValues={autoCompleteValues}
selectedLocation={props.getDestination}
></Autocomplete>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignSelf: "center",
position: "absolute",
top: Platform.OS === "android" ? 25 + 48 : 0 + 48,
width: Dimensions.get("window").width - 30,
zIndex: 500
},
parent: {
position: "relative",
flex: 1,
borderWidth: 2,
borderColor: "#AA2B45",
height: 48,
backgroundColor: "#fff",
flexDirection: "row",
alignItems: "center",
paddingLeft: 16,
paddingRight: 16,
justifyContent: "space-between"
}
}
export default function AutoComplete(props: AutoCompleteProps) {
const { autoCompleteValues } = props;
return (
<View style={styles.container}>
<FlatList
data={autoCompleteValues}
renderItem={({ item }: { item: POI }) => (
<TouchableOpacity onPress={() => console.log("Haal")} key={item.displayName} style={styles.list}>
<Text style={styles.text}>{item.displayName}</Text>
<Entypo name={"chevron-thin-right"} size={24} color={"#454F63"} />
</TouchableOpacity>
)}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
position: "absolute",
flex: 1,
width: Dimensions.get("window").width - 30,
top: 48,
borderWidth: 2,
borderColor: "#F7F7FA",
backgroundColor: "#F7F7FA",
zIndex: 999
},
list: {
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
paddingTop: 15,
paddingLeft: 10,
paddingBottom: 10,
borderBottomColor: "rgba(120, 132, 158, 0.08)",
borderBottomWidth: 1.4,
zIndex: 999
}
}
I know you solved your issue already, but you can use this magical library react-native-gesture-handler, import your Touchables from there and they don't care about being inside the parent views. You can touch them regardless.
Resolved this by dynamically adjusting the container height so that the touchableOpacity is within the container. The issue was I positioned the list outside of the parent (as intended by styling) but for onPress to work it has to be inside the parent.
let autocompleteHeight = autoCompleteValues.length * 65
<View style={[styles.container, {height: autocompleteHeight}]}>
I've created a list of tags in React Native, but I can't seem to make them wrap across multiple rows — here's what I have so far:
I want the tags to expand depending on the text - for example, the last tag in the screenshot should say Another tag - and wrap to a new line when needed.
I've rendered the tags using a ScrollView component, as I understand FlatList doesn't support wrapping - here's that code:
<ScrollView
contentContainerStyle={{
flex: 1,
flexDirection: 'row',
flexWrap: 'wrap',
}}
style={styles.tagContainer}>
{selectedTags
? selectedTags.map(tag => (
<Tag
style={{backgroundColor: tag.color}}
label={tag.label}
isList={false}
/>
))
: null}
</ScrollView>
styles: {
tagContainer: {
width: SCREEN_WIDTH - 20,
minHeight: 75,
},
}
Each tag is rendered using a Tag component that looks like this:
const Tag = ({label, style, isList, isChecked}) => {
const renderIcon = () => {
if (isList === true) {
return (
<Icon
name="ios-checkmark"
color={isChecked ? 'black' : 'white'}
size={36}
style={{alignSelf: 'center', margin: 5}}
/>
);
}
};
return (
<View
style={{
flex: 1,
flexDirection: 'row',
}}>
{renderIcon()}
<View style={isList ? styles.listContainer : styles.tagContainer}>
<Text style={[styles.tagStyle, style]}>{label}</Text>
</View>
</View>
);
};
const styles = {
tagContainer: {margin: 2, height: 30, flex: 1},
listContainer: {
flex: 1,
flexDirection: 'column',
width: 375,
height: 50,
borderBottomColor: '#dadade',
borderBottomWidth: 0.5,
justifyContent: 'center',
},
tagStyle: {
borderRadius: 4,
padding: 5,
marginLeft: 10,
flexDirection: 'row',
alignSelf: 'flex-start',
},
};
export {Tag};
Thanks!
Try below
<View style={{ flexDirection: 'row', flexWrap: 'wrap', flex: 1, alignItems: 'flex-start' }}>
{selectedTags
? selectedTags.map(tag => (
<Tag
style={{backgroundColor: tag.color}}
label={tag.label}
isList={false}
/>
))
: null}
</View>