react-native: [Android] TextInput doesn't scroll properly when restricting the height on an expanding TextInput
Description
I’m creating a InputText where I want to restrict the height to a maximum. When I do it the TextInput doesn’t automatically scroll when I write enough to add another line of text. That means I have to manually scroll down to see what I’m typing.
- It works on iOS as expected
- It works as expected if I’m setting a fixed height (
style={{height: 200}}
) - It works as expected if I don’t restrict the height (
style={{ height: Math.max(35, this.state.height) }}
)
Reproduction
class AutoExpandingTextInput extends React.Component {
constructor(props) {
super(props);
this.state = {
text: 'React Native enables you to build world-class application experiences on native platforms using a consistent developer experience based on JavaScript and React. The focus of React Native is on developer efficiency across all the platforms you care about — learn once, write anywhere. Facebook uses React Native in multiple production apps and will continue investing in React Native.',
height: 0,
};
}
render() {
return (
<TextInput
{...this.props}
multiline={true}
onChange={(event) => {
// onContentSizeChange doesn't work on Android, use onChange instead https://github.com/facebook/react-native/issues/11692
this.setState({ height: event.nativeEvent.contentSize.height });
}}
onContentSizeChange={(event) => {
this.setState({ height: event.nativeEvent.contentSize.height });
}}
onChangeText={(text) => {
this.setState({ text });
}}
style={{ height: Math.min(200, Math.max(35, this.state.height)) }}
value={this.state.text}
/>
);
}
}
Solution
?
Additional Information
- React Native version: 0.42
- Platform: Android
- Operating System: MacOS
About this issue
- Original URL
- State: closed
- Created 7 years ago
- Reactions: 30
- Comments: 64 (17 by maintainers)
Commits related to this issue
- TextInput: Fixed autoscroll to cursor on Android Summary: This feature was disabled for multiline textinputs in D3528202 ... seems without a good reason. The broken autoscroll-to-cursor feature is te... — committed to facebook/react-native by shergin 7 years ago
- TextInput: Fixed autoscroll to cursor on Android Summary: This feature was disabled for multiline textinputs in D3528202 ... seems without a good reason. The broken autoscroll-to-cursor feature is te... — committed to facebook/react-native by shergin 7 years ago
- TextInput: Fixed autoscroll to cursor on Android Summary: This feature was disabled for multiline textinputs in D3528202 ... seems without a good reason. The broken autoscroll-to-cursor feature is te... — committed to expo/react-native by shergin 7 years ago
- TextInput: Fixed autoscroll to cursor on Android Summary: This feature was disabled for multiline textinputs in D3528202 ... seems without a good reason. The broken autoscroll-to-cursor feature is te... — committed to vincentriemer/react-native-dom by shergin 7 years ago
- TextInput: Fixed autoscroll to cursor on Android Summary: This feature was disabled for multiline textinputs in D3528202 ... seems without a good reason. The broken autoscroll-to-cursor feature is te... — committed to bowerman0/react-native by shergin 7 years ago
- TextInput: Fixed autoscroll to cursor on Android Summary: This feature was disabled for multiline textinputs in D3528202 ... seems without a good reason. The broken autoscroll-to-cursor feature is te... — committed to bowerman0/react-native by shergin 7 years ago
- Implement Add Comment support. Other. Add Comment - Add new AddOrEditCommentScreen - Add redux and api support - Add navigation support - Add storybook story Other - For ejected app, update to RN 0.... — committed to tidepool-org/mobile by markyou 6 years ago
Yes, I am still working on this.
@shergin Is a fix for this already on master? Basically I’m trying to reproduce the same behvaviour as iOS on Android.
@guysegal use workaround as posted
0.51 is planned to be released sometime today (though unexpected things can happen, so give it a few extra days of buffer room).
Finally, 0bef872f3fc8b1cd78c574d03eacc886bef4e239 should fix this. If anyone can test it, I will appreciate that. 😄
@shergin @Palisand I’ve tracked the issue basing on RN 0.49-stable branch and this is a guilty method: https://github.com/facebook/react-native/blob/0.49-stable/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java#L121
I’ve created my own implementation of ReactEditText which looks like this:
Then I’ve overrided ReactTextInputManager like this:
and then I’ve copy-pasted the TextInput class and put my CustomTextInput here https://github.com/facebook/react-native/blob/0.49-stable/Libraries/Components/TextInput/TextInput.js#L42
And the issue is gone! UPDATE the above method has some drawbacks, please continue reading if you need a better workaround (you may don’t need it)
This is surely a pretty short workaround but it may require proper implementation and testing on master RN branch. I’m not sure why someone would not want the automatic scroll on the TextInput so I don’t know what is the purpose of the original implementation and which use cases it handles. I thought that maybe setting initial very long text on TextInput with restricted height would cause the TextInput to be scrolled to the bottom but
no, it didn’t break this behavior.(EDIT) it actually breaks this specific behavior. I’ve thought about setting some kind of ‘autoScroll’ prop on input field’s focus event and resetting it on input field’s blur event but I’m not sure if this is a proper way of doing this. Anyway, below you can find this implementation if anyone is interested on it. I’m not proud of it but hey, it works for basic use cases - not sure if this is a proper way of handling, especially after @shergin changes in master here https://github.com/facebook/react-native/commit/c550f27a4e82402b966567d7b79a8b1f1d1491a5 . Also @Palisand I’m notifying you here in case if you’re interested.@jonasb @shergin This is also happening on RN 0.46.1. Simply including
is enough to cause what appears to be disabling automatic scrolling, even on inputs of fixed height!
I see it’s fixed in 0.52 instead: https://github.com/facebook/react-native/commit/0bef872
Hi @dead23angel I dont know about that. It could require fixing the actual library code?
Somebody pointed out a flaw in my code though so here is an updated version that works in case a user scrolls up and is editing part of the text they wrote:
https://snack.expo.io/rJHCrEYef good for React Native >= 50.0 (to get this to work for React Native < 50.0 just add the onContentSizeChange method to the text input like the example above)
This is obviously pretty messy and I actually like the simplicity of @konradkierus version, but since I am using Expo for react native I do not have the luxury of using native code. It needs to be 100% javascript.
The key here is updating the component’s state using the ScrollView’s
onScroll
method to capture the new currentY
position of the TextInput any time the scroll position changes.After that, anytime the
onContentSizeChange
method is called we save the new content height to state. We also use thescrollTo
method to scroll to our newY
position. Our newY
position increments the currentY
position by the difference of the new content height and the previous content height we saved in state.Since this is only an Android problem, I will probably only use this component for my Android rendering and let my iOS rendering stay the same. I am kind of concerned about what performance issues if any could come from calling setState too much
An upstream fix would be super ideal 👍
Confirmed on RN 0.46.4, with:
Hey @mannol, cherry-picking Android fixes is a fairly involved process because you first need to setup your project to build Android from source. It’s been a long time since I set up the Android build in my project, but all I remember is that it took a while to get working.
If you are building Android from source, the fastest way to ‘cherry-pick’ is to actually just copy/paste the changes to
ReactEditText.java
from this commit into yournode_modules
directory, and then use a tool like patch-package to preserve the changes acrossyarn
/npm install
s.@ide Any idea when the 0.51 will be released? @jamesreggio Any idea how to cherrypick this commit into a project initialized with react-native init (react-native-git-upgrade doesn’t work with 0.51.0-rc.3 which should have this commit)?
Thanks!
@Palisand great comment, thanks for the heads up! Did not see that commit, i was on a old version 😉
@shukerullah After @shergin’s changes,
TextInput
s for both iOS and Android have an intrinsic size. You do not need to useonContentSizeChange
orautoGrow
to controlmultiline
input size anymore if you’re on master; try out the RNTester app and rejoice! To restore Android’s cursor-following / auto-scrolling, you need to use @konradkierus’s changes which, at the very least, involve havingReactEditText
’sisLayoutRequested
method always returnfalse
. To add cursor-following to iOS it is a little more involved if you want to use my method (see my previous comment), but you also have the option of using @baijunjie’s react-native-input-scroll-view.@stoffern the
onChange
callback no longer accepts an event that includescontentSize
as of this commit. Which version of RN are you using?seriously @shergin thank you so so much. This is such a save!
@shergin
It would be nice to make this commit to version 0.47, because I like the @riryjs code is great to update the packages
I found a solution that works for my purposes so figured I’d share
This code works for React Native >=50.0: https://snack.expo.io/r1y4tXVxz
This code works for React Native <50.0: https://snack.expo.io/S1wXbNNxM
There are some nested ScrollViews since KeyboardAvoidingView is a ScrollView but it works pretty well as a workaround without having to do native code. The key is using the ScrollView’s scrollToEnd anytime the content size changes.
I only use KeyboardAvoidingView because I’m building a chat app and the message box is at the bottom of the screen.
Still there for me as well on 0.50.3
@LEEY19 read this https://facebook.github.io/react-native/docs/native-components-android.html Previously I gave you a link to writing a custom module, this link shows how to implement custom component (extending view managers). If you still won’t know how to properly do it then please ask for help in StackOveflow to not spam here.
@Palisand Well, I just tried to fix/enable it, but I failed. So, yes, the current state is: layout is working, (auto)scrolling is not (and I don’t know how to fix that, yet). But, it should be (easy) fixable. 😂
@Palisand I can confirm 100%.
By looking at the code in react-native-autogrow-input, I was able to create a Component that solves this problem for me (I’ve only tested it on Android). This is a messy hack because I use two TextInput. The user sees only one of them. The hidden TextInput handles onContentSizeChange() while the visible one receives user input, grows & scrolls appropriately. The two TextInput communicate with each other via the component state. The component requires two props:
minHeight
andmaxHeight
. Feel free to customize this for your use case or let me know if you have a better solution.@stoffern which workaround are you referring to? I didn’t find a workaround for the case where max height is defined