-
Notifications
You must be signed in to change notification settings - Fork 24.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
KeyboardAvoidingView has no effect on multiline TextInput #16826
Comments
I have a similar issue Environmentnode: 8.9.1 Steps to Reproduce
Expected BehaviorMultiline TextInput should be above the soft keyboard. Actual BehaviorSoft keyboard covers TextInput. Reproducible Demo |
|
KeyboardAvoidingView works fine with multiline TextInput because i am using them myself. Initially they would not work for me. To solve my problem i removed the height on the TextInput and set the behavior to "padding". The "flex: 1" you have on the KeyboardAvoidingView might be the problem i think or its the scrollview. But KeyboardAvoidingView definitely works fine with multiline. |
Referring to my snippet posted above, there's no height on the TextInput, and KeyboardAvoidingView's behavior is set to padding. Its style needs Try the code with and without multiline set. It fails with multiline set, but the same code works for single line TextInputs. |
Same problem here! |
@peacechen I have exactly the same problem like you. Need to add flex: 1 for the ScrollView as the wrapper. And it works if I remove the prop multiline={true}. Any solution for this? |
This should work but doesn't. Relevant: facebook/react-native#16826
The same issue。 |
If anyone still is looking for a fix, you could try
Its a dirty hack but it does the job, what it does it when user clicks on the input it would be clicking on the single line and the keyboard will scroll to that line then after 1 seconds (you can adjust this, i just found 1 seconds to be good with our app) it would focus on the multiline. The value and onChangeText makes sure that when the user star typing they would have the same value except the single line has transparent text. The downside is when a user clicked the multiple line, the cursor wont go to the location they clicked but it would go to the end. |
@monmonja That's a creative work-around. I wonder if it could also be done by setting the I don't see the multiline prop in the first TextInput, but I assume it's supposed to be in there. |
Has anyone found a good solution for this? |
@peacechen I tried to implement your suggestion but it has a strange effect and doesn't work. Something's flickering and the keyboard eventually disappears. |
same problem here and still have no solution |
I too facing the same issue. It works fine if multiline is set to false and not if set to true. My TextInput does not have any height. Any solutions?? |
A workaround for this is to make a reference to the parent scrollview and call its scrollTo method to the multilined TextInput coordinates whenever onFocus is called.
|
same problem here only on IOS it is working fine on android |
This has been quite frustrating for us as well.. Seems like the only consistent way to do this is by scrolling manually as @jasonchoibiz suggested. It's an ugly workaround though! |
there is news about this problem? |
Still having this. Tried the suggested solutions. |
same problem here |
Same issue, here's a simple snack for anyone to play with: https://snack.expo.io/r1qpj0k5Q |
I've tried this and it works: https://github.com/baijunjie/react-native-input-scroll-view |
react-native version 0.56.1 |
it is working; <KeyboardAvoidingView behavior="padding" style={Platform.OS !== 'android' && { flex: 1 }}>
<ScrollView>
...
<TextInput ... />
...
</ScrollView>
</KeyboardAvoidingView> |
@recepkoseoglu It works on non-multiline Inputs. Try on multiline. |
5 years and no direct solution yet?! |
Damn it's June 2023 and the only "solution" is |
I think FB has bigger concerns right now lol |
2023 and not a proper way to avoid keyboard over input from reactnative .... |
july 2023... |
Bump |
Hi folks, After a lot of search I've a workaround for my case, The thing I wanted was not have a scrollable TextInput but a non-scrollable infinite height as size of text as gives and this view contained to a ScrollView working properly with a KeyboardAvoidingView, Voila: import React, { useState } from 'react';
import { SafeAreaView, ScrollView, TextInput, View, KeyboardAvoidingView, Keyboard, TouchableWithoutFeedback } from 'react-native';
import { Header } from 'react-native/Libraries/NewAppScreen';
export default function App(): JSX.Element {
const [text, setText] = useState(`
One
Two
Three
Four
Five`);
const [textInputHeight, setTextInputHeight] = useState(40);
const handleTextChange = (newText: any) => {
setText(newText);
};
return (
<SafeAreaView style={{ flex: 1 }}>
<KeyboardAvoidingView behavior='padding' style={{ flex: 1 }}>
<TouchableWithoutFeedback onPress={Keyboard.dismiss}>
<ScrollView
style={{
backgroundColor: '#00ffff32',
borderWidth: 1,
borderColor: '#0000ff',
}}
>
<Header />
<View style={{}}>
<TextInput
style={{
borderWidth: 1,
height: Math.max(40, text.split('\n').length * 20),
}}
onChangeText={handleTextChange}
value={text}
onContentSizeChange={event => {
const { height } = event.nativeEvent.contentSize;
setTextInputHeight(Math.max(40, height));
}}
multiline={true}
scrollEnabled={false}
/>
</View>
</ScrollView>
</TouchableWithoutFeedback>
</KeyboardAvoidingView>
</SafeAreaView>
);
} I wrapped this functionality in a CustomInputView component of course |
Hi, I'm new to React-Native and ran into the same problem. const [isScrollEnabledForTextArea, setIsScrollEnabledForTextArea] = useState<boolean>(false);
<TextArea
keyboardType={'default'}
isInvalid={invalid}
value={value}
onChangeText={onChange}
onBlur={() => {
setIsScrollEnabledForTextArea(false);
}}
autoCompleteType={'off'}
autoCapitalize={'none'}
autoCorrect={false}
scrollEnabled={isScrollEnabledForTextArea}
onFocus={() => {
// dirty hack, the KeyboardAvoidingView cant handle an input if it has multiline text
setTimeout(() => setIsScrollEnabledForTextArea(true), SEC_IN_MS);
}}
></TextArea> I'm using NativeBase with |
So setting |
For anyone still looking for a solution to this. I created an NPM package, expo-clear-input that is a solution to the above by working on any platform (web, ios, android) and in both single and multiline A little |
It is 2024 now... Still no direct fix? |
fix? |
return code return (
<KeyboardAvoidingView
behavior={Platform.OS === 'ios' ? 'padding' : undefined}
enabled
style={styles.avoid}
keyboardVerticalOffset={0}>
<View style={styles.inputContainer}>
<TextInput
style={styles.input}
editable
multiline
textAlignVertical="top"
onChangeText={newText => setText(newText)}
value={text}
maxLength={maxLength}
autoFocus={true}
/>
<View style={styles.counterContainer}>
<Text style={styles.counter}>{`${text.length}/${maxLength}`}</Text>
</View>
<DotButton style={{width: '100%'}}>
<DotButton.ButtonText>Send</DotButton.ButtonText>
</DotButton>
</View>
</KeyboardAvoidingView>
); style inputContainer: {
maxHeight: 500,
flex: 1,
justifyContent: 'center',
alignItems: 'center',
marginHorizontal: 20,
},
input: {
flex: 1,
borderWidth: 1,
borderColor: '#000',
borderRadius: 10,
alignSelf: 'stretch',
},
counterContainer: {
alignSelf: 'stretch',
},
counter: {
textAlign: 'right',
marginTop: 4,
},
avoid: {
flex: 1,
}, for those who have a similar structure as me |
I believe it is an issue with RCTScrollViewComponentView.mm and/or RCTUITextView. The behaviour is not automatic on iOS, some libs provide it like IQKeyboardManager. I tested the workaround from comment-1148477911 (branch). My understanding is that the native iOS implementation of ScrollView will keep the current scroll position automatically, for example:
step 3) does not work on iOS when using multiline TextInput (UITextView), while it works when using single line TextInput (UITextField). Probably, the fact that UITextView can scroll, breaks this functionality. Maybe the iOS implementation of UITextView/ScrollView keeps the position constant based on the contentOffset, but as we have 2 scrollviews (ScrollView scrolls and UITextView scrolls), the implementation manages the content offset of the TextInput multiline, instead of the parent scrollview. KeyboardAvoidingView just wraps a view with react-native/packages/react-native/Libraries/Components/Keyboard/KeyboardAvoidingView.js Lines 232 to 246 in 12155c4
as you can see, there is no native impl of KeyboardAvoidingView, simply it changes the ScrollView height after opening the keyboard, the scrollview height is decreased by the height of the keyboard, but the scrollview fails to scroll to the previous position I also added to the below example, logic to scroll down the scrollview after opening the keyboard.
CLICK TO OPEN TESTS RESULTS
import * as React from 'react';
import {
Keyboard,
StyleSheet,
KeyboardAvoidingView,
ScrollView,
View,
Text,
TextInput,
} from 'react-native';
const RNTesterApp = () => {
const [text, setText] = React.useState(
'a line 1 \n a line 2 \n a line 3 \n a line 4 \n a line 5 \n a line 6 \n a line 7 \n',
);
let scrollViewRef = React.useRef(null);
const [isScrollEnabled, setIsScrollEnabled] = React.useState(true);
const onKeyboardWillShow = () => {
console.log('onKeyboardWillShow');
setIsScrollEnabled(false);
if (scrollViewRef) {
console.log('scrollToEnd');
scrollViewRef.scrollTo({x: 0, y: 300});
}
};
function onKeyboardDidShow() {
console.log('onKeyboardDidShow');
setIsScrollEnabled(true);
}
React.useEffect(() => {
const subKWS = Keyboard.addListener('keyboardWillShow', onKeyboardWillShow);
const subKDS = Keyboard.addListener('keyboardDidShow', onKeyboardDidShow);
return () => {
subKWS.remove();
subKDS.remove();
};
}, []);
return (
<KeyboardAvoidingView style={{flex: 1, marginTop: 100}} behavior="padding">
<ScrollView
ref={ref => (scrollViewRef = ref)}
keyboardShouldPersistTaps={'handled'}
maintainVisibleContentPosition={{minIndexForVisible: 1}}>
<View style={{padding: 12}}>
<Text style={styles.text}>MESSAGE 1</Text>
<Text style={styles.text}>MESSAGE 2</Text>
<Text style={styles.text}>MESSAGE 3</Text>
<Text style={styles.text}>MESSAGE 4</Text>
<Text style={styles.text}>MESSAGE 5</Text>
<Text style={styles.text}>MESSAGE 6</Text>
<Text style={styles.text}>MESSAGE 7</Text>
<Text style={styles.text}>MESSAGE 8</Text>
<Text style={styles.text}>MESSAGE 9</Text>
<Text style={styles.text}>MESSAGE 10</Text>
<Text style={styles.text}>MESSAGE 11</Text>
</View>
<TextInput
multiline={true}
placeholder={'Type something here...'}
onChangeText={setText}
value={text}
scrollEnabled={true}
style={styles.input}
/>
</ScrollView>
</KeyboardAvoidingView>
);
};
export default RNTesterApp;
const styles = StyleSheet.create({
text: {
fontSize: 20,
padding: 40,
},
input: {
height: 50,
},
}); I may consider working on this issue and publishing a fix if requested by the community. https://stackoverflow.com/a/20052756/7295772 https://stackoverflow.com/a/69811662/7295772 Similar issues, but on Android are #25239 and #30373 (comment) |
@fabOnReact Thanks for the great details on the problem, Fabrizio |
Thanks, but I decided to not contribute anymore to facebook/react-native. |
`<KeyboardAvoidingView <ScrollView ref={component => { this.myScrollView = component; }}> This is how this will work. You can also try keyboard aware scroll view , or in android manifiest.xml can change the adjust keyboard. or if nothing works then we have antother alternative a prop called tabBarHideOnKeyboard: true. |
@Paraschoudhary176 Thanks for your thoughts, and here is my solution: const App = () => {
const scrollViewRef = useRef(null)
const textInputRef = useRef(null)
const onFocus = () => {
if (Platform.OS === 'ios') {
if (scrollViewRef.current && textInputRef.current) {
textInputRef.current.measureLayout(
scrollViewRef.current,
(x, y, width, height) => {
setTimeout(() => {
scrollViewRef.current.scrollTo({y: y, animated: true});
}, 500); // 500ms just work fine.
},
() => {},
);
}
}
}
return (
<KeyboardAvoidingView>
<ScrollView ref={scrollViewRef}>
<TextInput
ref={textInputRef}
multiline={true}
numberOfLines={3}
onFocus={onFocus} />
</ScrollView>
</KeyboardAvoidingView>
)
} |
Hello, maintainer and creator of I think KeyboardAwareScrollView from Theoretically similar behavior can be backported to Anyway, if you have such examples and if you think, that something is not working or should work in a different way - feel free to open issues in react-native-keyboard-controller repository 👀 |
in 2024, Here is my working fix, scrollEnabled={false} did most of the magic. I honestly hope it helps someone here. <KeyboardAwareScrollView |
disabling scroll on a scrollview .... not a fix at all , if you have like 10 inpunt inside to show ? ( |
+1 |
I dont wanna depends on another library for this bug, here is my solution: Custom hook: import { useRef } from 'react'
// import { doSomethingAtSecondX } from '@core/utils'
interface DoSomethingAtSecondX {
callback: () => void
seconds: number
}
export const doSomethingAtSecondX = (params: DoSomethingAtSecondX) => {
const { callback, seconds } = params
setTimeout(callback, seconds * 1000)
}
interface MoveScrollTo {
x: number
y: number
}
export const useMoveScroll = () => {
const scrollRef = useRef() as any
const moveScrollTo = ({ x, y }: MoveScrollTo) =>
scrollRef.current.scrollTo({ x, y, animated: true })
const moveScrollToDown = (pxToDown: number) => {
if (scrollRef.current) {
doSomethingAtSecondX({
callback: () => moveScrollTo({ x: 0, y: pxToDown }),
seconds: 0.35
})
}
}
return {
scrollRef,
moveScrollToDown
}
} Component: const { scrollRef, moveScrollToDown } = useMoveScroll()
return (
<ScrollView
ref={scrollRef}
showsVerticalScrollIndicator={false}
....
/>
<Input
multiline
numberOfLines={5}
placeholder='write comments here...'
onFocus={() => moveScrollToDown(450)}
onChangeText={setComments}
/>
</ScrollView>
) Hope this help 🐰 |
@chrisdev3001 can you tell me where i can get this "doSomethingAtSecondX" |
+1 |
I have updated the code... it was just a little helper function 👀 |
why is so hard to work with keyboards in rn???? :((((( |
@ftaibi this code works for me ! `import React from 'react'; interface Props { const KeyboardAvoidingComponent: React.FC = ({ children, style }) => { export default KeyboardAvoidingComponent; use as <KeyboardAvoidingComponent style={{flex: 1}}> |
KeyboardAvoidingView only works with single-line TextInputs. When the
multiline
prop is set, KeyboardAvoidingView does not shift the TextInput at all.Is this a bug report?
Yes
Have you read the Contributing Guidelines?
Yes
Environment
Environment:
OS: macOS Sierra 10.12.6
Node: 7.0.0
npm: 3.10.8
Watchman: 4.7.0
Xcode: 9.1
Packages: (wanted => installed)
react-native: 0.49.3
react: 16.0.0-beta.5
Target Platform: iOS (10.3)
Steps to Reproduce
<TextInput>
component withmultiline
prop set.Expected Behavior
Multiline TextInput should scroll above the soft keyboard.
Actual Behavior
Soft keyboard covers multiline TextInput.
Reproducible Demo
The text was updated successfully, but these errors were encountered: