I am trying to make react native UI using FlexBox. But when keyboard pops up, it messes up the UI. Take a look at screenshots and code. I think something is wrong with my FlexBox code.
It is trying to divide remaining screen space between elements according to given flex value.
<View style={loginWrapperStyle}>
<Card>
<View style={logoWrapperStyle}>
<Image
source={require('./logo.png')}
style={logoStyle} />
</View>
<View style={loginFormStyle}>
<TextBox
placeholder='Useraname/Email'
autoCorrect={false}
value={this.state.username}
onChangeText={(val) => this.setState({ username: val })} />
<TextBox
placeholder='Password'
secureTextEntry
autoCorrect={false}
value={this.state.password}
onChangeText={(val) => this.setState({ password: val })} />
</View>
<View style={loginButtonWrapperStyle}>
<Button>
Login
</Button>
</View>
</Card>
</View>
const styles = {
loginWrapperStyle: {
padding: 15,
backgroundColor: '#7CB142',
flex: 1,
},
logoWrapperStyle: {
flex: 2
},
logoStyle: {
flex: 1,
width: null,
height: null,
resizeMode: 'contain',
marginTop: 10
},
loginFormStyle: {
flex: 1
},
loginButtonWrapperStyle: {
flex: 1,
padding: 15,
justifyContent: 'center',
alignItems: 'center',
}
};
You can try out KeyboardAvoidingView which is the most simple solution and easiest to install. You've to wrap your code within KeyboardAvoidView and then add a behavior prop to it.
There's also a KeyboardAwareScrollView(https://github.com/APSL/react-native-keyboard-aware-scroll-view) which will solve your issue.
There's a good demonstration of these at: https://medium.freecodecamp.com/how-to-make-your-react-native-app-respond-gracefully-when-the-keyboard-pops-up-7442c1535580
Related
I tried basically every answer from this question and nothing seems to work: React native text going off my screen, refusing to wrap. What to do?
I am facing the same issue where my text goes off-screen and seems to be operating at a width of about 130% or so.
Here is the screen I render the list:
<View style={styles.container}>
<FlatList
data={messagePreviewData}
renderItem={({ item }) =>
<ChatPreview
readMessage={item.readMessage}
imgUri={item.imgUri}
username={item.username}
time={item.time}
message={item.message}
/>
}
keyExtractor={(item, index) => item.username + index}
/>
</View>
const styles = StyleSheet.create({
container: {
backgroundColor: colors.neutralOne,
flex: 1,
}
});
And here is the ChatPreview component, where the message text goes off-screen:
const ChatPreview = (props: ChatPreviewProps) => {
const { readMessage, imgUri, username, time, message } = props;
return (
<View style={styles.container}>
<View style={styles.leftContainer}>
<View style={styles.badgeAvatarContainer}>
<Avatar
rounded
source={{ uri: imgUri }}
size={scaledSize(50)}
/>
</View>
<View style={styles.usernameMessageContainer}>
<Text style={styles.username}>{username}</Text>
<Text style={styles.messagePreview} numberOfLines={2} ellipsizeMode='tail'>
{message} // this is what's going off screen
</Text>
</View>
</View>
<Text style={styles.time}>{time}</Text>
</View>
);
}
const styles = StyleSheet.create({
container: {
flexDirection: 'row',
justifyContent: 'space-between',
padding: 10,
},
leftContainer: {
flexDirection: 'row'
},
badgeAvatarContainer: {
flexDirection: 'row',
alignItems: 'center',
marginRight: 10
},
usernameMessageContainer: {
// I have tried putting many things here and nothing seems to work
},
username: {
color: colors.neutralEight,
fontFamily: fonts.bodyTwoBold.fontFamily,
fontSize: fonts.bodyTwoBold.fontSize,
lineHeight: fonts.bodyTwoBold.lineHeight,
},
messagePreview: {
color: colors.neutralFour,
fontFamily: fonts.captionOne.fontFamily,
fontSize: fonts.captionOne.fontSize,
lineHeight: fonts.captionOne.lineHeight,
},
time: {
color: colors.neutralFour,
fontFamily: fonts.captionTwo.fontFamily,
fontSize: fonts.captionTwo.fontSize,
lineHeight: fonts.captionTwo.lineHeight
}
});
It might be worth setting flex:1 from parent down to the child where the content is going off screen. I've had issues where I've forgotten to do it and it's been messed up.
Essentially you could add flex:1 to every style in ChatPreview to try it out, It won't look super nice probably but you should see if the issue is fixed I believe and tweak it from there.
coincidently i was doing a similar thing yesterday. So as you are using flex-direction row , thus , the text (which tries to get all the width given to it, by default 100%) goes out of screen as now 100% is what you said 130%. Now to restrict it, we just need to restrict its width. So set width on the text, maybe only 60% or 70% and it will work fine.
Im trying to use KeyboardAvoidingView, but i got no result with them.
styled view with styled components:
export const Container = styled.View({
backgroundColor: primary,
flex: 1,
alignItems: 'center',
});
export const ImageView = styled.View({
marginTop: 16,
alignItems: 'center',
justifyContent: 'center',
});
export const InputView = styled.View({
width: '100%',
marginTop: 16,
});
export const TextView = styled.View({
marginLeft: 42,
marginRight: 42,
marginTop: 22,
alignItems: 'center',
justifyContent: 'center',
});
export const BottomView = styled.View({
flex: 1,
justifyContent: 'flex-end',
alignItems: 'center',
width: '100%',
});
And here is my layout. I set behavior = padding trying to solve my problem, but not works.
<KeyboardAvoidingView behavior="padding" style={{flex: 1}}>
<Container>
{load && <Loading />}
<TextView>
<Text value={diaryStrings.title} isModalMessage />
</TextView>
<TextView>
<Text value={diaryStrings.hintMessage} isModalMessage />
</TextView>
<TextView>
<Text value={diaryStrings.tipMessage} isModalMessage />
</TextView>
<ImageView>
<ImageSvg name={'calendar'} />
</ImageView>
<InputView>
<Input
placeholder={diaryStrings.diaryName}
placeholderTextColor={tertiary}
maxLength={20}
iconName="book"
onChangeText={text => {
setDiaryNameError('');
setDiaryName(text);
}}
maskType="nomask"
error={diaryNameError}
value={diaryName}
/>
<Input
placeholder={diaryStrings.initialDate}
placeholderTextColor={tertiary}
maxLength={10}
iconName="date-range"
onChangeText={text => {
setDiaryInitDateError('');
setDiaryInitDate(text);
}}
maskType="datetime"
error={diaryInitDateError}
value={diaryInitDate}
/>
</InputView>
<BottomView>
<Button
title={'next'}
hasBackgroundColor={true}
onPress={async () => {
setLoad(true);
await validateForm();
setLoad(false);
}}
/>
<Button
title="Cancel"
onPress={() => {
navigation.navigate('Home');
}}
/>
</BottomView>
</Container>
i think im using some property that invalidates KeyboardAvoindView. I dont wanna use an ScrollView, its possible solve this? Any one can help?
I've struggled to get KeyboardAvoidingView working properly too, what worked for me was using these props for KeyboardAvoidingView and wrapping content in ScrollView:
<KeyboardAvoidingView enabled keyboardVerticalOffset={90} behavior={ Platform.OS === 'ios' ? 'padding' : false } style={{ flex: 1 }} >
<ScrollView>
{all content here}
</ScrollView>
</KeyboardAvoidingView>
Also I had to use TextInput from react-native which needed to have scrollEnabled={false} prop
I want to add prefix to my text input and I would like to know how to do it.
Text Input Code
<TextInput
style={styles.inputs}
placeholder="Mobile Number"
keyboardType="number-pad"
underlineColorAndroid="transparent"
onChangeText={mobile_number => this.setState({mobile_number})}
/>
Final output I want
You can do it like that:
render() {
return (
<View style={styles.inputContainer}>
<Text style={styles.prefix}>+94</Text>
<TextInput
placeholder="Mobile Number"
keyboardType="number-pad"
underlineColorAndroid="transparent"
onChangeText={mobile_number => this.setState({ mobile_number })}
/>
</View>
)
}
const styles = StyleSheet.create({
inputContainer: {
borderWidth: 1,
flexDirection: 'row',
alignItems: 'center',
backgroundColor: 'white',
marginHorizontal: 10,
borderRadius: 10
},
prefix: {
paddingHorizontal: 10,
fontWeight: 'bold',
color: 'black'
}
})
If you don't want the prefix to be editable, use a label:
<View>
<Label />
<TextInput />
<View>
You can use a text mask. Try this
https://github.com/react-native-community/react-native-text-input-mask
To handle phone number inputs
https://www.npmjs.com/package/react-phone-number-input
You can do it combination of two textinput. One is for prefix and other is for input text.
like this:
<View>
<TextInput /> // Text or dropdown pick, something else
<TextInput />
<View>
I have a component that renders the following:
return (
<KeyboardAvoidingView behavior="position">
<View style={styles.container}>
<View style={styles.messagesContainer}>
</View>
<SafeAreaView>
<View style={styles.inputView}>
<TextInput style={styles.input} />
<Button title="submit" />
</View>
</SafeAreaView>
</View>
</KeyboardAvoidingView>
)
With stylesheet:
const styles = StyleSheet.create({
container:{
height: "100%"
},
messagesContainer: {
backgroundColor: "red",
flex: 1
},
inputView: {
flexDirection: "row",
alignItems: "center",
padding: 5,
height: 24
},
input: {
height: 20,
backgroundColor: "white",
flex: 1
}
});
This view is rendered as a screen in a react-navigation StackNavigation.
I'd like the view to move up to make space for the keyboard, but it doesn't seem to move up far enough.
I know it's moving it up, because if I add some padding to the bottom of my container:
I've also wondered whether the SafeArea component is messing up the calculations of how far up the view should be moved, but it doesn't seem so.
I could tweak that bottom padding until the text input shows up right above the keyboard, but that seems like a flaky solution that'd require different values for different devices, orientations, keyboard layouts, etc.
Is there a more robust solution?
Need some modification in styling try this
return (
<KeyboardAvoidingView behavior="position" style={styles.containerWraper}>
<View style={styles.container}>
<View style={styles.messagesContainer}>
</View>
<SafeAreaView>
<View style={styles.inputView}>
<TextInput style={styles.input} />
<Button title="submit" />
</View>
</SafeAreaView>
</View>
</KeyboardAvoidingView>
)
Styles
const styles = StyleSheet.create({
container:{
flex: 1,
justifyContent: 'center'
},
containerWraper:{
flex: 1,
justifyContent: 'center'
},
messagesContainer: {
backgroundColor: "red",
flex: 1
},
inputView: {
flexDirection: "row",
alignItems: "center",
padding: 5,
height: 24
},
input: {
height: 20,
backgroundColor: "white",
flex: 1
}
});
Try NativeBase instead, that has better approach
I'm trying to basically create a search input field with a cancel button next to it but the TextInput doesn't show and the formatting is broken.
I'm using the shoutem ui toolkit https://shoutem.github.io/docs/ui-toolkit/components/text-input
How do I set the styles so that the input box to shows up correctly? I can't see the input box and the button margins seem off.
Should I use a Row instead of a View? However using a row doesn't seem to work well either.
Does anyone have an example of a form with buttons next to inputs using shoutem UI?
<View styleName="horizontal space-between wrap">
<TextInput
placeholder="Search"
autoFocus={ true }
returnKeyType="search"
clearButtonMode="while-editing"
/>
<Button styleName="right-icon" onPress={() => {
this.setModalVisible(!this.state.modalVisible)
}}>
<Text>Cancel</Text>
</Button>
</View>
I tried switching to a plain TextInput rather than a shoutemUI text input and I added this style, but how do I get the width to automatically stretch? How do I fix the padding on the button?
The code
<View styleName="horizontal" style={ StyleSheet.flatten(styles.searchRow)}>
<TextInput
placeholder="Search"
autoFocus={ true }
returnKeyType="search"
clearButtonMode="while-editing"
style={ StyleSheet.flatten(styles.searchBox) }
/>
<Button styleName="right-icon" style={{padding: 5, margin:5}} onPress={() => {
this.setModalVisible(!this.state.modalVisible)
}}>
<Text>Cancel</Text>
</Button>
</View>
And The Style
searchBox: {
borderWidth: 0.5,
padding: 5,
margin: 5,
paddingLeft:10,
width: 200,
alignSelf: 'stretch',
height:40,
backgroundColor: 'white',
borderColor: '#d3d3d3',
},
This is how you can implement a search field with a search icon and a clear icon:
<View styleName="container full-width md-gutter-left sm-gutter-right">
<View style={style.container} styleName="horizontal sm-gutter-horizontal v-center">
<Icon name="search" style={style.searchIcon} />
<TextInput style={style.input} value={value} />
{
value ?
<Button styleName="clear tight">
<Icon
name="clear-text"
style={style.clearIcon}
/>
</Button>
}
</View>
<Button styleName="clear">
<Subtitle>Cancel</Subtitle>
</Button>
</View>
The style names come from the UI toolkit's theme. Here are the relevant styles for the component:
{
clearIcon: {
color: '#2c2c2c',
opacity: 0.5,
},
container: {
backgroundColor: '#f0f0f0',
borderRadius: 5,
flex: 1,
height: 30,
},
searchIcon: {
color: '#888888',
fontSize: 16,
},
input: {
backgroundColor: '#f0f0f0',
color: '#888888',
flex: 1,
fontSize: 15,
height: 30,
paddingVertical: 6,
placeholderTextColor: '#888888',
selectionColor: '#888888',
},
},
You'll probably need to make a few modifications, but this should help you implement the search field you need. If you don't want to or can't use styleNames, just look up what styles they define.