I'm looking to dismiss the keyboard when the user clicks on anywhere outside the keyboard or the input, but the keyboard is not being dismissed when I click elsewhere:
<TouchableWithoutFeedback style={styles.container} onPress={Keyboard.dismiss}>
<View style={styles.inputContainer}>
<TextInput
placeholder="Search Term"
style={styles.input}
onChangeText={setSearch}
value={search}
returnKeyType="search"
onSubmitEditing={handleSubmit}
/>
</View>
</ TouchableWithoutFeedback>
The styling is pretty standard:
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
inputContainer: {
position: 'absolute',
top: stackHeaderHeight + 10,
height: height * .1,
width: '100%',
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
},
You need to change your onPress code of TouchableWithoutFeedback
<TouchableWithoutFeedback style={styles.container} onPress={()=> Keyboard.dismiss()}>
</ TouchableWithoutFeedback>
Sample working code.
render() {
return (
<TouchableWithoutFeedback onPress={()=>Keyboard.dismiss()} >
<View style={{ flex: 1 }}>
<TextInput returnKeyType="search" style={{borderWidth:1,borderColor:'grey',marginTop:100,height:50,marginHorizontal:50}}/>
</View>
</TouchableWithoutFeedback>
);
}
I think you have a problem with your style properties. Please check on your container and inputcontainer style properties. If you have any ScrollView in your render method add following
<ScrollView keyboardShouldPersistTaps='always'>
Related
I'm trying to make a custom header component with an icon that can either toggle the navigation drawer or navigate the user back (or anywhere), the button is working fine on Android but doesn't seem to register the onPress on iOS.
I tried playing with position absolute and relative but the issue persisted.
//Component code
const HeaderArrow: React.FC<Props> = (props) =>{
return(
<View style={[styles.HeaderContainer, props.HeaderStyle]}>
<Icon name={props.iconName} size={35} color={props.iconColor} onPress={() => props.navigateMeBack()}/>
<View style={{position: 'relative', top: 0, left: 0, right: 0, bottom: 0, justifyContent: 'center', alignItems: 'center'}}>
<Text style={[styles.TextStyle, props.TextEdited]}>
{props.HeaderText}
</Text>
</View>
</View>
)
}
const styles = EStyleSheet.create({
HeaderContainer:{
flexDirection: 'row',
backgroundColor: '#f8f8f8',
alignItems: 'center',
width: WIDTH,
paddingVertical: '5rem',
marginHorizontal: '5rem',
},
TextStyle:{
fontSize: '18rem',
fontWeight: 'bold',
textAlign: 'center',
color: Colors.mainHeader,
}
})
// Main screen code<HeaderArrow
HeaderText={'Sign up (1 of 2)'}
HeaderStyle={{backgroundColor: 'red'}}
TextEdited={GlobalStyles.headerTextStyle}
navigateMeBack={() => backToLogin()}
iconName={'arrow-left'}
iconColor={Colors.mainForeGround}
/>
You can use this way
<TouchableOpacity onPress={() => props.navigateMeBack()} >
<Icon
name={props.iconName}
size={35}
color={props.iconColor}
/>
</TouchableOpacity>
I'm new to coding and react native, so sorry if this is a stupid question.
I'm having issues rendering a hamburger icon from the following code. It works as expected on Android but not iOS.
import React from 'react';
import { StyleSheet, Text, View, TouchableOpacity, Image } from 'react-native';
import { totalPoints, totalBucks } from '../datasets/UserData.js';
export class Navbar extends React.Component {
constructor(props){
super(props);
}
burgerPress = value => {
this.props.onPress();
}
render(){
var points = totalPoints;
var bucks = totalBucks;
return(
<View style={styles.row}>
<Text style={styles.column} />
<Text style={styles.column}>
<Image source={require('../../assets/coins.png')} style={{ width: 30, height: 30, resizeMode: 'contain'}}/>
{" "}{ points }
</Text>
<Text style={styles.column}>
<Image source={require('../../assets/bills.png')} style={{ width: 40, height: 40, resizeMode: 'contain'}}/>
{" "}{ bucks }
</Text>
<View style={styles.column}>
<TouchableOpacity onPress={() => this.burgerPress()} style={{width: 40, height: 40, justifyContent: 'center', alignItems: 'center'}}>
<Image source={require('../../assets/hamburger.png')} resizeMode={'contain'} style={{ width: 40, height: 40, backgroundColor: 'lightblue', tintColor: '#ffffff', justifyContent: 'center', alignItems: 'center'}}/>
</TouchableOpacity>
</View>
</View>
);
};
};
const styles={
row: {
flex: 1,
alignItems: 'flex-end',
flexDirection: 'row',
borderBottomWidth: 1,
borderColor: "#000000",
padding: 5,
justifyContent: 'center'
},
column: {
flex: 1,
alignItems: 'center',
flexDirection: 'column',
justifyContent: 'center'
}
}
The coins and bills icons load properly on both platforms. The hamburger loads on android, but on iOS, all I get is the background color. If I delete the backgroundColor and tintColor, it renders nothing, so I think the issue is that it is not importing the image at all but only on iOS. Is there any way to get this to work?
iOS display(unexpected)
Android display(expected)
I don't see what your styles.column are specified as but as a test I would give your TouchableOpacity a width and height as well. Then try to set justifyContent: center and alignItems: center to make sure the image is not being hidden for some reason.
You might also need to specify the resizeMode={'contain'} prop in Image rather than just declaring it in your image style.
I am trying to use the KeyboardAvoidingView with behavior="padding".
When I am trying to enter any text in TextInput, the TextInput field is not moving up. I have added a small view in the end which is moving up but the the view above it.
I have also with KeyboardAvoidingView height property with offset. It was working few components like 2 TextInputs. But when I add all the components the UI goes insane and behave jumbled up.
Any any idea whats happening over here?
Here the link of tutorial which I have followed.
render() {
return (
<View style={styles.backgroundContainer}>
<Loader
loading={this.state.isLoading} />
<KeyboardAvoidingView
keyboardVerticalOffset={10}
style={styles.mainContainer}
behavior='padding' >
<View style={styles.formContainer}>
<View style={[styles.centerContainer, { marginTop: 40 }]}>
<Image source={require('./../../Resources/logo.png')} />
<Text style={{ fontWeight: 'bold', color: 'gray', fontSize: 25 }}>AppName</Text>
<Text style={styles.loginMsg}> Login to your Account </Text>
</View>
<View style={styles.inputFieldsContainer}>
<Image style={{ width: 30, height: 30, margin: 5 }} source={require('./../../Resources/logo.png')} />
<TextInput
placeholder='Email'
returnKeyType='next'
keyboardType='email-address'
onChangeText={(value) => this.setState({ userEmail: value })}
onSubmitEditing={() => this.passwordInput.focus()}
style={styles.inputFields} />
</View>
<View style={styles.inputFieldsContainer}>
<Image style={{ width: 30, height: 30, margin: 5, }} source={require('./../../Resources/logo.png')} />
<TextInput
returnKeyType='go'
secureTextEntry
placeholder='Password'
ref={(input) => this.passwordInput = input}
onChangeText={(value) => this.setState({ password: value })}
style={styles.inputFields} />
</View>
<View style={styles.buttonContainer}>
<Button
fontSize='8'
color='gray'
title='Remember Me'
onPress={() => {
console.log('Remember Me Clicked');
}} />
<Button
color='gray'
title='Forgot Password?'
onPress={() => {
console.log('Forgot Password Clicked');
}} />
</View>
<TouchableOpacity
style={styles.buttonLogin}
onPress={() => {
console.log('Login Clicked');
}}
>
<Text style={{ fontSize: 20, fontWeight: 'bold', color: 'white' }}>Login</Text>
</TouchableOpacity>
<View style={{ height: 1, backgroundColor: 'gray', marginTop: 20, marginBottom: 1 }}>
</View>
<View style={[styles.centerContainer, { marginBottom: 10 }]}>
<Text style={styles.loginMsg}>Don't have a Account</Text>
<TouchableOpacity
style={styles.buttonRegister}
onPress={() => navigate('Register')} >
<Text style={styles.buttonRegisterText}>REGISTER NOW</Text>
</TouchableOpacity>
</View>
</View>
<View style={{ height: 10, backgroundColor: '#628499', }}>
</View>
</KeyboardAvoidingView>
</View>
);
}
const styles = StyleSheet.create({
backgroundContainer: {
flex: 1, backgroundColor: 'green'
},
mainContainer: {
flex: 1, margin: 25,
borderWidth: 1, borderRadius: 5, borderColor: 'gray',
backgroundColor: 'white',
justifyContent: 'space-between'
},
formContainer: {
flex: 1, paddingLeft: 25, paddingRight: 25
},
centerContainer: {
alignItems: 'center', marginBottom: 10,
},
loginMsg: {
margin: 10,
fontSize: 20, color: 'gray'
},
inputFieldsContainer: {
flexDirection: 'row', margin: 10,
borderWidth: 1, borderRadius: 5, borderColor: 'gray',
},
inputFields: {
flexGrow: 1,
marginTop: 5, marginBottom: 5,
height: 30,
backgroundColor: 'rgba(255,255,255,0.4)',
paddingHorizontal: 10,
},
buttonContainer: {
flexDirection: 'row',
justifyContent: 'space-between'
},
buttonLogin: {
alignItems: 'center', height: 40, marginTop: 10, marginLeft: 50, marginRight: 50, padding: 5,
backgroundColor: '#2980b9',
borderWidth: 1, borderRadius: 5, borderColor: 'gray'
},
buttonRegister: {
alignItems: 'center', height: 40,
marginLeft: 50, marginRight: 50
},
buttonRegisterText: {
fontSize: 20, fontWeight: 'bold', color: 'gray'
},
loading: {
position: 'absolute',
left: 0, right: 0, top: 0, bottom: 0,
alignItems: 'center', justifyContent: 'center'
}, });
I used KeyboardAvoidingView, it also doesn't work.
I found this solution, You can take the base code.
Installation
npm i react-native-keyboard-aware-scroll-view --save
Usage
import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view'
<KeyboardAwareScrollView>
<View>
<TextInput />
</View>
</KeyboardAwareScrollView>
You can find it here
The way it worked for me was to use position as behavior and -70 as vertical offset. Any non negative integer was creating a huge unused space when the keyboard pops up.
<KeyboardAvoidingView
style={styles.container}
behavior={Platform.OS === 'ios' ? 'position' : 'height'}
keyboardVerticalOffset={Platform.OS === 'ios' ? -70 : 70}
enabled>
<ScrollView>
...
</ScrollView>
</KeyboardAvoidingView>
<KeyboardAvoidingView
style={styles.mainContainer}
behavior="padding"
enabled
>
<View>.......................</View>
</KeyboardAvoidingView>
'Enabled or disabled KeyboardAvoidingView' should be add.
Keep in mind is always your top Parent with flex:1 then the child is then you text input container
<KeyboardAvoidingView style={{ flex: 1 }}
behavior={Platform.OS === "ios" ? "position" : null} enabled>
<ScrollView>
<View>
<View >
<Text maxFontSizeMultiplier={1.5} >
Sign in to your account{" "}
</Text>
<View
behavior="padding"
enabled
>
<TextInput
placeholder="Email address"
placeholderTextColor={Colors.grey}
style={styles.textInput}
onChangeText={(e) => setEmail(e.trim())}
autoCapitalize="none"
returnKeyType={"done"}
/>
</View>
</View>
</ScrollView>
</KeyboardAvoidingView>
// 2nd Solutions use this package
npm i react-native-keyboard-aware-scroll-view --save
import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view'
<KeyboardAwareScrollView>
<View>
<TextInput />
</View>
</KeyboardAwareScrollView>
I have a login form with two text inputs stacked vertically and a container view with two buttons below the inputs:
I want the two buttons to stretch to fill the width of the button container (red), so each button would take half its size. However I can't get it to work. I've tried various combinations of flex* properties with no luck.
In native iOS I would use a UIStackView for this with orientation = horizontal. React Native documentation says that pretty much any layout can be achieved with flexbox.
This is what my component looks like right now:
import React, {Component} from 'react';
import {KeyboardAvoidingView, TextInput, View, StyleSheet} from 'react-native';
import Button from 'react-native-button';
export default class Login extends Component {
render() {
return (
<KeyboardAvoidingView style={styles.container}>
<TextInput
placeholder="LOGIN"
placeholderTextColor="#505050"
style={styles.input}/>
<TextInput
placeholder="PASSWORD"
placeholderTextColor="#505050"
style={styles.input}/>
<View style={styles.buttonContainer}>
<Button
onPress={() => this.logIn()}
style={[styles.button, styles.loginButton]}>
Log in
</Button>
<Button
onPress={() => this.register()}
style={[styles.button, styles.registerButton]}>
Register
</Button>
</View>
</KeyboardAvoidingView>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingHorizontal: 16,
backgroundColor: 'lightgray'
},
input: {
height: 40,
marginBottom: 12,
paddingHorizontal: 8,
backgroundColor: 'white'
},
buttonContainer: {
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'red'
},
button: {
padding: 8,
color: 'white',
backgroundColor: 'steelblue'
},
loginButton: {
marginRight: 8
}
});
If I add flex: 1 to the button style they become:
What am I doing wrong?
Yes. Its because of the react-native-button component. You have to use the containerStyle property of the Button component to style the container.
import React, {Component} from 'react';
import {KeyboardAvoidingView, TextInput, View, StyleSheet} from 'react-native';
import Button from 'react-native-button';
export default class Login extends Component {
render() {
return (
<KeyboardAvoidingView style={styles.container}>
<TextInput
placeholder="LOGIN"
placeholderTextColor="#505050"
style={styles.input}/>
<TextInput
placeholder="PASSWORD"
placeholderTextColor="#505050"
style={styles.input}/>
<View style={styles.buttonContainer}>
<Button
onPress={() => this.logIn()}
style={styles.buttonText}
containerStyle={styles.button}
>
Log in
</Button>
<Button
onPress={() => this.register()}
style={styles.buttonText}
containerStyle={styles.button}
>
Register
</Button>
</View>
</KeyboardAvoidingView>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingHorizontal: 16,
backgroundColor: 'lightgray'
},
input: {
height: 40,
marginBottom: 12,
paddingHorizontal: 8,
backgroundColor: 'white'
},
buttonContainer: {
height: 60,
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'red'
},
button: {
flex: 2,
padding: 8,
backgroundColor: 'steelblue',
alignSelf: 'stretch',
justifyContent: 'center',
},
buttonText: {
color: 'white',
}
});
Currently here is my login form
<ScrollView centerContent>
<View style={styles.container}>
<TextInput style={styles.input} placeholder="email"
keyboardType="email-address"
value={this.state.email}
onChangeText={email => this.setState({email})} />
<TextInput style={styles.input} placeholder="password"
secureTextEntry
value={this.state.password}
onChangeText={password => this.setState({password})} />
<View style={{flexDirection: 'row'}}>
<TouchableHighlight style={styles.button} onPress={this.login.bind(this)}>
<Text style={styles.buttonText}>Login</Text>
</TouchableHighlight>
</View>
<TouchableHighlight onPress={this.props.toSignup}>
<Text>To Signup</Text>
</TouchableHighlight>
</View>
</ScrollView>
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
button: {
flex: 1,
padding: 8,
margin: 5,
borderWidth: 1,
borderRadius: 4,
borderColor: '#2c45ec',
backgroundColor: '#2c45ec'
},
buttonText: {
color: '#ffffff'
},
input: {
height: 36,
padding: 4,
margin: 5,
textAlign: 'center',
fontSize: 18,
borderWidth: 1,
borderColor: '#48BBEC',
borderRadius: 8,
color: '#48BBEC'
}
});
And here is what it looks like
I have 2 issues with this code:
When I tap a text input, the keyboard shows up. When I tap another text input, the keyboard is dismissed. I have to tap that text input again for the keyboard to come back.
When I tap a text input, the keyboard shows up, but the content is not recentered, thus the keyboard covers up some of the bottom part of the login form.
I inspected the login form in the Facebook iOS app, and it can persist keyboard when tapping on another input, and dismiss keyboard when tapping elsewhere, and it can also recenter the content when the keyboard shows up.
How can I achieve similar effect of the Facebook iOS app?