As of now, _ScrollResponder_ implements method to scroll native handle to the keyboard. Handle, usually, is a text input but it could be whatever component...
Current solution:
/**
* This method should be used as the callback to onFocus in a TextInputs'
* parent view. Note that any module using this mixin needs to return
* the parent view's ref in getScrollViewRef() in order to use this method.
* @param {any} nodeHandle The TextInput node handle
* @param {number} additionalOffset The scroll view's top "contentInset".
* Default is 0.
* @param {bool} preventNegativeScrolling Whether to allow pulling the content
* down to make it meet the keyboard's top. Default is false.
*/
scrollResponderScrollNativeHandleToKeyboard: function(nodeHandle: any, additionalOffset?: number, preventNegativeScrollOffset?: bool) {
this.additionalScrollOffset = additionalOffset || 0;
this.preventNegativeScrollOffset = !!preventNegativeScrollOffset;
UIManager.measureLayout(
nodeHandle,
ReactNative.findNodeHandle(this.getInnerViewNode()),
this.scrollResponderTextInputFocusError,
this.scrollResponderInputMeasureAndScrollToKeyboard
);
},
Issue with current solution:
Handle scrolls to bottom of the keyboard even if it's not covered by the keyboard itself. This looks very bad and causes unnecessary distraction.
Proposed solution:
What I propose is to implement very similar method which would measure handle's dimensions and it's Y position relative to viewport/screen (not "document", which might and ofter is higher than viewport/screen height) and scroll only if handle is under the keyboard. In order to to so, _ScrollResponder_ has to retain scroll offset (content offset) in one of it's method.
// ScrollResponder.js
scrollResponderHandleScroll: function(e: Event) {
this.state.observedScrollSinceBecomingResponder = true;
this.props.onScroll && this.props.onScroll(e);
// retain contentOffset
this.contentOffset = e.nativeEvent.contentOffset;
},
// Expose method which solves the issue
scrollResponderScrollNativeHandleToKeyboardIfCovered: function(nodeHandle: any, additionalOffset?: number, preventNegativeScrollOffset?: bool) {
this.additionalScrollOffset = additionalOffset || 0;
this.preventNegativeScrollOffset = !!preventNegativeScrollOffset;
UIManager.measureLayout(
nodeHandle,
ReactNative.findNodeHandle(this.getInnerViewNode()),
this.scrollResponderTextInputFocusError,
this.scrollResponderInputMeasureAndScrollToKeyboardIfCovered
);
},
// Measure handle's position and decide whether to scroll or not to.
// Under the hood, original `scrollResponderInputMeasureAndScrollToKeyboard` method is used.
scrollscrollResponderInputMeasureAndScrollToKeyboardIfCovered(left: number, top: number, width: number, height: number) {
var bottommostCoord = top + height - this.contentOffset.y;
var keyboardScreenY = Dimensions.get('window').height;
if (this.keyboardWillOpenTo) {
keyboardScreenY = this.keyboardWillOpenTo.endCoordinates.screenY;
}
if (bottommostCoord - keyboardScreenY > 0) {
// Use existing method to do measurements and scroll to handle to keyboard.
this.scrollResponderInputMeasureAndScrollToKeyboard(left, top, width, height);
}
},
Questions:
What I am not sure about is scrollResponderScrollNativeHandleToKeyboardIfCovered which is mostly copy-paste of scrollResponderScrollNativeHandleToKeyboard. The only difference is it's "on success" callback for UIManager.measureLayout call.
scrollscrollResponderInputMeasureAndScrollToKeyboardIfCovered be implemented or in order to avoid almost 1:1 copy should scrollscrollResponderInputMeasureAndScrollToKeyboard accept one more argument? scrollscrollResponderInputMeasureAndScrollToKeyboard accepts one more argument wouldn't it be too many arguments (it's already too many to my taste)? scrollscrollResponderInputMeasureAndScrollToKeyboard to break current API and have something likescrollscrollResponderInputMeasureAndScrollToKeyboard(layout: Object, dontScrollIfNotCovered: boolean);If we clear those questions and you are interested, I'd be happy to send PR.
Can you confirm if this is still an issue for you? I'm not able to replicate this on current master.
@chirag04 could you point me to recent updates of what changed, related to this issue? I've seen there is KeyboardAvoidingView available now, which could be used to shrink inner ScrollView. I am about to try that out...
Is there a way to get KeyboardAvoidingView to work with a TextInput that's inside a ScrollView?
@npomfret Your best option there is https://github.com/APSL/react-native-keyboard-aware-scroll-view
@npomfret I use this: https://gist.github.com/chirag04/d7a7d58f4afc9520a51f511ce7f67788
@chirag04 It didn't work for me.
Closing this issue because it has been inactive for a while. If you think it should still be opened let us know why.
Most helpful comment
Is there a way to get KeyboardAvoidingView to work with a TextInput that's inside a ScrollView?