I am trying to make a form with multiple input fields using react-native. I want the form submit button to remain at the bottom of the screen. I've used the following structure
<KeyboardAwareScrollView
contentContainerStyle={{
backgroundColor: "black",
flexGrow: 1
}}
enableOnAndroid={true}
>
<View style={styles.container}>
<View style={styles.formContainer}>
{/*Form input components here*/}
</View>
<View style={styles.buttonContainer}>
<Button
icon={<Icon name="back" size={24} color="white" />}
onPress={props.setModalVisible}
buttonStyle={styles.backButton}
/>
<Button
buttonStyle={styles.button}
containerStyle={{ flex: 1 }}
title="Update Info"
onPress={props.setModalVisible}
/>
</View>
</View>
</KeyboardAwareScrollView>
The container has style
container: {
padding: 10,
backgroundColor: "green",
flex: 1
},
The form container has style
formContainer: {
padding: 15,
flex: 1,
backgroundColor: "blue"
},
Button container has style
buttonContainer: {
padding: 15,
flexDirection: "row",
backgroundColor: "yellow",
marginTop: 'auto'
},
Using the above code the button sticks to the bottom when there is no keyboard as I expected. I've added background color for easy visualization. Image -
Form View
But when I click on a text field and scroll up I see that the container "shrinks" and the bottom of the screen is black and button is now close to input fields. Background color of KeyboardAwareScrollView contentContainerStyle fills the bottom when I [fully scroll to bottom][3]
How do I make sure that the button still sticks to the bottom in scrollview and the content container height remains the same as screen height?
I am using "react-native-keyboard-aware-scroll-view": "0.8.0",
I've tried removing marginTop: 'auto' from the buttonContainer, fixing the height of the container and all sorts of combinations with flexGrow and flex on KeyboardAwareScrollView.
Related
I have a web view for my login form that I want to automatically scroll up when the keyboard is triggered without pushing my Text component up as well. Is there a way to have a component ignore the keyboard so it remains at the bottom beneath the keyboard while retaining that behavior?
The following is that code of what I have tried. It does push the view up and my text component stays at the bottom but I'm left with a grey box above my keyboard.
<KeyboardAvoidingView
style={{flex: 1}
behavior={Platform.OS === 'ios' ? null : 'padding'}
keyboardVerticalOffset={Platform.OS === 'ios' ? 0 : headerHeight - 10}> // if I do -200 it will remove the grey box but the view does not shift when the keyboard is toggled
<ScrollView>
<WebView
automaticallyAdjustContentInsets={false}
style={{flex: 1, alignSelf: 'stretch', width: Dimensions.get('window').width, height: Dimensions.get('window').height},}
source={{ uri }}
/>
<Text style={{position: 'absolute', left: 0, right: 0, textAlign: 'center', bottom: '5%', backgroundColor: 'white'},}>
For more information:{' '}
<Text
style={{ color: 'blue' }}
onPress={() =>
Linking.openURL(redirectURI)
}>
Tap here!
</Text>
</Text>
</ScrollView>
</KeyboardAvoidingView>
How do I fix this?
Did you test putting the KeyboardAvoidingView inside the ScrollView?
I have a <ScrollView />, wrapped inside an Animatable.View (a wrapper for Animated.View with a few standard animations)
Like this:
<Animatable.View
animation={this.state.businessSlide}
duration={500}
delay={this.state.delay}
useNativeDriver={false}
easing={"ease-in-cubic"}
onAnimationEnd={this.handleBusinessPop}
>
<ScrollView
style={{ width: "100%", alignSelf: "center", height: 175, zIndex: 999 }}
contentContainerStyle={{ alignSelf: "center", justifyContent: "center", alignItems: "center", flexGrow: 1 }}
onScroll={(event) => this.businessScroll(event)}
scrollEventThrottle={16}
>
{this.state.businessMerchants.map((merchant, index) => (
<Business
merchant={merchant}
key={merchant.id}
isCurrentItem={index === this.state.currentItemIndex}
/>
))}
<View style={{ height: 100 }} />
</ScrollView>
</Animatable.View>
The view slides in from the bottom the position.
I believe this is due to some sort of overlap or something, as if I set the translate distance to 0, (i.e. it animates to where it would be normally without the animated view), it scrolls fine.
This only happens on Android, iOS works as expected.
I have one TextInput with some predefined text.
The problem is that on Android the text is displayed at the bottom of the text input. I tryed with textAlignVertical: 'top' to display it at top position, but without success the strange thing is that on the IOS is working perfectly
React Native TextInput Multiline
multiline
If true, the text input can be multiple lines. The default value is false. It is important to note that this aligns the text to the top on iOS, and centers it on Android. Use with textAlignVertical set to top for the same behavior in both platforms.
current behaviour:
the text is displayed at the bottom
desired behaviour:
the text to be displayed at the top
index.js
render() {
return (
<View style={{
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#ecf0f1',
paddingTop: 20,
paddingBottom: 50,
paddingLeft: 20,
paddingRight: 20}}>
<TextInput
style={{
flex: 1,
textAlignVertical: 'top',
borderWidth: 1}}
autoCapitalize={'none'}
autoCorrect={false}
value={this.state.textTabs}
multiline={true}
onChangeText={(text) => {this.setState({textTabs: text})}}
underlineColorAndroid={'transparent'}
editable={true}
/>
</View>
);}
Thanks in advance
I've been making Layouts for Screens in React Native with Flexbox for a while now and hadn't run into any trouble until today when I had to make this very simple layout:
A header section (not a NavBar).
A content section → A ScrollView with a FlatList inside of it.
A footer section.
I want the content section to be 3 times bigger than the Header and the Footer, so naturally I set the flex to 1 (header), 3 (content), 1 (footer).
No matter what, the content remains as if it has flex: 1.
The only way I could control the layout the way I wanted was to leave content's flex: 1 and set both footer and header to flex: 0.33.
I suspect it might have something to do with ScrollView's contentContainerStyle prop which I set to flexGrow: 1, flexShrink: 1.
Here's a minimal example which reproduces this.
Update 2:
I've been pointed out that I shouldn't be using a ListView wrapped inside a ScrollView since the following can happen:
It might lead to some weird behaviors like onEndReached firing continuously.
Wrapping the ListView inside the ScrollView makes the parent scroll action dominate the child scroll action which leads only ScrollView to scroll.
Okay, I'm not sure why this works, but found the solution after hours of trying:
After the step mentioned in Update 1, I added the following style flexGrow: 0 to the FlatList inside the ScrollView and the content became centered and decreasing the content's size until it becomes scrollable works perfectly as well.
Basically this is the resulting code:
render() {
return (
<View style={{ flex: 1 }}>
<View style={{ flex: 1 }}>
<Text>HEADER</Text>
</View>
<View style={{ flex: 6 }}> // Change this to affect ScrollView size
<ScrollView contentContainerStyle={{ flexGrow: 1, justifyContent: 'center' }}>
<FlatList
data={listItems}
renderItem={Item}
keyExtractor={(index, item) => item}
style={{ flexGrow: 0 }} // This was the solution to centering
/>
</ScrollView>
</View>
<View style={{ flex: 1 }}>
<Text>FOOTER</Text>
</View>
</View>
);
}
Here's the final Working Solution if you'd like to try it.
Update 1:
Managed to control ScrollView size with Flex normally (that is using integer flex values as intended in the first place) by wrapping ScrollView inside a View with flex: 1.
The downside is that if I set the Scrollable section (content) to a flex value high enough so It's not scrollable anymore, content doesn't display centered. Not even if justifyContent: 'center' is applied.
Here's UPDATE 1 example.
With minimal modification it works for me, I used this style:
const styles = StyleSheet.create({
screen: {
backgroundColor: 'lightgray',
flex: 1,
},
header: {
flex: 0.33,
backgroundColor: 'lightblue',
justifyContent: 'center',
alignItems: 'center',
},
scrollView: {
flex: 1,
},
footer: {
backgroundColor: 'lightpink',
flex: 0.33,
alignItems: 'center',
justifyContent: 'center',
},
});
Full code >>> https://snack.expo.io/Hk9tbHR4Q
This is the result:
version of RN is 0.41.2
does anyone know how to stop View's that use flexbox for sizing, from automatically "shrinking" their height if a TextInput element is used in one of the Views? It's probably easier to illustrate by example, and to be clear, you can see that these are View's nested inside a <Modal>.
Here is the view when no keyboard is open. Same on both.
Here's what happens when TextInput has the focus. I dont want these views to adjust as they have, above the keyboard. I want the yellow and blue colored View's to remain 'full size' - exactly as illustrated in the iOS screenshot.
This same code, on iOS, does not move/adjust the View's (above the keyboard). That's the behavior I want on Android too.
Here is the sample render method code. It's just a standard template RN project with a change to the render method to test this out.
I tried inserting android:windowSoftInputMode="adjustNothing" into AndroidManifest.xml but had no effect. I'm sure it's just a prop or other manifest setting. Hoping someone can let me know?
render() {
return (
<View style={styles.container}>
<Modal
animationType={'slide'}
transparent={false}
onRequestClose={() => console.log('sd')}
>
<View style={{flex:1, backgroundColor: 'lightgrey'}}>
<View style={{
//height:300,
flex: 1,
backgroundColor: 'yellow',
alignItems: 'center',
justifyContent: 'center',
}}>
<View style={{
margin: 10,
//height:100,
width: 200,
justifyContent: 'center',
backgroundColor: 'green'}}>
<TextInput style={{height: 40, backgroundColor: 'orange'}} />
</View>
</View>
<View style={{
//height:200,
flex: 1,
backgroundColor: 'blue',
}}>
</View>
</View>
</Modal>
</View>
);
}
Did you try wrapping all of the contents within a ScrollView and then a child KeyboardAvoidingView?
I had exactly the same problem, and instead of adding ScrollView everywhere I just made a little change in AndroidManifest.xml:
instead of: android:windowSoftInputMode="adjustResize"
i wrote: android:windowSoftInputMode="adjustPan"
Worked like a charm for me