I am trying to leverage this component with custom components, events, and even a multiline TextInput (custom growing component). I think moving forward what I need is to be able to fire an event to force an update. This would be recalculating scroll position based on a view or component changing it's size.
What I've tried thus far is to add an update function to the render method.
return (
<ScrollableComponent
...
onScroll={this._onScroll}
update={this.update}
/>
)
Now, some help moving forward to force this update would be much appreciated. So far I've tried the following methods with no success.
scrollIntoView(el) // Weird behavior, see below
scrollToFocusedInput(el) // Weird JSON stringify errors
this._resetKeyboardSpace() // this throws due to it being a Keyboard listener event.
this._updateKeyboardSpace // this throws due to it being a Keyboard listener event.
scrollIntoView(el) does something weird. When calling this, the screen bounces around. What I'm looking for is just to nudge the keyboard up to the bottom of this component when it's starting to scroll off screen.
Perhaps getting the coords (in conjunction with _measureElement) of the component and then firing resetScrollToCoords would work.
The code I ended up with, and similar results to scrollIntoView (with no surprise since the code was borrowed from around there).
update = async (element) => {
if (!this._rnkasv_keyboardView || !element) {
return
}
const [
parentLayout,
childLayout
] = await Promise.all([
this._measureElement(this._rnkasv_keyboardView),
this._measureElement(element)
])
const getScrollPosition = this._defaultGetScrollPosition
const { x, y, animated } = getScrollPosition(parentLayout,
childLayout, this.position)
this.scrollToPosition(x, y, animated)
}
Any and all help is much appreciated.
Further experimentation has lead me to try to calculate the position by hand without helper functions. The result is still unsightly.
update = async (element) => {
...
let x = 0
let y = Math.max(0, childLayout.y - parentLayout.y)
const animated = false
this.scrollToPosition(x, y, animated)
}
I think a new approach of trying to determine the offset of textInputBottomPosition might be a solution. Some code I found could hint at further experimentation.
UIManager.measureInWindow(
currentlyFocusedField,
(x: number, y: number, width: number, height: number) => {
const textInputBottomPosition = y + height
const keyboardPosition = frames.endCoordinates.screenY
const totalExtraHeight =
this.props.extraScrollHeight + this.props.extraHeight
if (Platform.OS === 'ios') {
if (
textInputBottomPosition >
keyboardPosition - totalExtraHeight
) {
this._scrollToFocusedInputWithNodeHandle(
currentlyFocusedField
)
}
}
}
Finally have a solution! Here's the working code. I'll try to upload a video later today.
In component file:
render() {
return (
<KeyboardAwareScrollView extraScrollHeight={ 100 } ref='KeyboardAwareScrollView'>
<TextInput ... />
</KeyboardAwareScrollView>
)
}
componentDidUpdate() {
let keyboardScrollView = this.refs.KeyboardAwareScrollView
if (keyboardScrollView)
keyboardScrollView.update()
}
In KeyboardAwareHOC.js
update = () => {
const currentlyFocusedField = TextInput.State.currentlyFocusedField()
const responder = this.getScrollResponder()
if (!currentlyFocusedField || !responder) {
return
}
this._scrollToFocusedInputWithNodeHandle(
currentlyFocusedField
)
}
I'm not sure why this.getScrollResponder() is required, there's nothing else in the code that implies this changes any variables. However without this code, the ScrollView component will continue to bounce aimlessly while adding new lines to a multiline TextInput.
Another oddity is why bypassing _scrollToFocusedInputWithNodeHandle with scrollToFocusedInput altogether makes this behave so weirdly; the code for that is pretty simple. Might have something to do with ReactNative.findNodeHandle(nodeID)? I see nothing in here really worth value on x,y.
_scrollToFocusedInputWithNodeHandle = (
nodeID: number,
extraHeight?: number,
keyboardOpeningTime?: number
) => {
if (extraHeight === undefined) {
extraHeight = this.props.extraHeight
}
const reactNode = ReactNative.findNodeHandle(nodeID)
this.scrollToFocusedInput(
reactNode,
extraHeight + this.props.extraScrollHeight,
keyboardOpeningTime !== undefined
? keyboardOpeningTime
: this.props.keyboardOpeningTime || 0
)
}
Hi @bugs181!
Would you like to send us a PR for this? Thanks!
Sure thing, please check #251
This worked for me. Had to update the KeyboardAwareHOC.js manually. When will this be available as a standard part of the package?
@alexcittadini this was merged in
https://github.com/APSL/react-native-keyboard-aware-scroll-view/releases/tag/v0.6.0, please check that you're using the latest version.
Most helpful comment
Finally have a solution! Here's the working code. I'll try to upload a video later today.
In component file:
In
KeyboardAwareHOC.jsI'm not sure why
this.getScrollResponder()is required, there's nothing else in the code that implies this changes any variables. However without this code, theScrollViewcomponent will continue to bounce aimlessly while adding new lines to a multilineTextInput.Another oddity is why bypassing
_scrollToFocusedInputWithNodeHandlewithscrollToFocusedInputaltogether makes this behave so weirdly; the code for that is pretty simple. Might have something to do withReactNative.findNodeHandle(nodeID)? I see nothing in here really worth value on x,y.