Recently I needed a scroll into view functionality just like it works in the web. Sadly, I had to implement it myself as I use this library and it does not implement such method.
I now have a working prototype of the method that receives a ref into the view that you want to scroll and magically scrolls to it and I would really like if this library implemented such method but I'm not sure if such functionality is out of scope here.
So, what do you think?
Hello @sebasgarcep!
So if I understand correctly, do you want to being able to scroll directly into a passed view? Can you post a snippet of how your solution looks like in the actual source code?
This is what I've got:
import React, { Component } from 'react'
import { UIManager, findNodeHandle } from 'react-native'
import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view'
export default class CustomScrollView extends Component {
_container = null
_contentOffset = 0
scrollIntoView = async (view) => {
if (!this._container || !view) {
return
}
const [
parentLayout,
childLayout
] = await Promise.all([
this._measureElement(this._container),
this._measureElement(view)
])
const top = childLayout.y - parentLayout.y + this._contentOffset
this._container.scrollToPosition(0, Math.max(0, top))
}
_measureElement = (element) => {
const node = findNodeHandle(element)
return new Promise((resolve) => {
UIManager.measureInWindow(node, (x, y, width, height) => {
resolve({ x, y, width, height })
})
})
}
_onRef = (view) => {
this._container = view
}
_onScroll = (event) => {
this._contentOffset = event.nativeEvent.contentOffset.y
if (this.props.onScroll) {
this.props.onScroll(event)
}
}
render () {
return (
<KeyboardAwareScrollView
{...this.props}
ref={this._onRef}
onScroll={this._onScroll}
scrollEventThrottle={1}
/>
)
}
}
And to use this method:
import React, { Component } from 'react'
import CustomScrollView from '...'
import { Button, StyleSheet, View } from 'react-native'
const styles = StyleSheet.create({
block: {
alignSelf: 'stretch',
height: 600
},
red: {
backgroundColor: 'red'
},
blue: {
backgroundColor: 'blue'
}
})
export default class TestBehaviour extends Component {
_redView = null
_blueView = null
_scroll = null
_onRef = (property, view) => {
this[property] = view
}
_scrollIntoView = (ref) => {
if (this._scroll) this._scroll.scrollIntoView(ref)
}
render () {
return (
<CustomScrollView ref={scroll => this._onRef('_scroll', scroll)}>
<View
ref={view => this._onRef('_redView', view)}
style={[styles.block, styles.red]}
/>
<View
ref={view => this._onRef('_blueView', view)}
style={[styles.block, styles.blue]}
/>
<Button
title='Scroll to Red'
onPress={() => this._scrollIntoView(this._redView)}
/>
<Button
title='Scroll to Blue'
onPress={() => this._scrollIntoView(this._blueView)}
/>
</CustomScrollView>
)
}
}
I haven't tested all of this but I believe it is correct and the CustomScrollView is copy-pasted from what we have in production. We are using React v16.2.0 and the React Native that comes with Expo v24.
Inspired by this method from the DOM: https://developer.mozilla.org/es/docs/Web/API/Element/scrollIntoView
Hi @sebasgarcep!
Can you open us a PR?
Hi, did a PR ever come out of this?
@TSMMark Not really, because this only works for a ScrollView and I don't know if that's okay by @alvaromb. If that's okay I can proceed. It's not much work really.
Don't mind to add this feature, as long as it is properly documented and exposed into the component API.
That's great, I'd love to see this feature. I'm about to implement it manually right now but will be more than happy to refactor to use this in the future. Thanks for the snippets @sebasgarcep
Working on the PR now!
I tried using the sample but I am getting an error while accessing the function
import { KeyboardAwareScrollView, KeyboardAwareHOC, KeyboardAwareListView } from 'react-native-keyboard-aware-scroll-view'
render() {
<KeyboardAwareScrollView innerRef={ref => { this.scroll = ref }} keyboardShouldPersistTaps='handled'>
<SelectionView
lang="en-US"
placeholder={label}
minuteInterval={10}
ref={ref => this.inspectionPicker = ref}
scrollToPicker={(evt) => {
//TODO : Check this
/* this._scrollToInput(evt.target)
this.scroll.props.scrollIntoView(evt.target)*/
}}
defaultSelectedValue={this.state.value[this.state.listPosition][name] == '' ? '' : this.state.value[this.state.listPosition][name]}
onConfirm={(option) => {
}}
onSelect={(option) => {
console.log(option.value)
let value = _.cloneDeep(this.state.value)
value[this.state.listPosition][name] = option.value
this.setState({
value
})
}}
onClear={() => {
let value = _.cloneDeep(this.state.value)
value[this.state.listPosition][name] = ''
this.setState({
value
})
}}
options={optionTypes}
>
</SelectionView>
</KeyboardAwareScrollView>
}
}
_scrollToInput(reactNode) {
// Add a 'scroll' ref to your ScrollView
this.scroll.scrollToFocusedInput(reactNode)
}


@TSMMark @sebasgarcep Could you please guide me which approach should I follow.
I also tried using KeyboardAwareHOC scrollIntoView function but getting an error
@iosfitness I think you need to call this.scroll.scrollIntoView instead of this.scroll.props.scrollIntoView.
Also, if I recall correctly, this method only works on KeyboardAwareScrollView.
Hey, I tried it but still I'm getting the same error. Function not found
```
placeholder={label}
minuteInterval={10}
ref={ref => this.inspectionPicker = ref}
scrollToPicker={(evt) => {
const ReactNativeComponentTree = require('ReactNativeComponentTree');
const elem = ReactNativeComponentTree.getInstanceFromNode(evt.target);
this._scrollIntoView(elem)
}}
defaultSelectedValue={this.state.value[this.state.listPosition][name] == '' ? '' : this.state.value[this.state.listPosition][name]}
onConfirm={(option) => {
}}
onSelect={(option) => {
console.log(option.value)
let value = _.cloneDeep(this.state.value)
value[this.state.listPosition][name] = option.value
this.setState({
value
})
}}
onClear={() => {
let value = _.cloneDeep(this.state.value)
value[this.state.listPosition][name] = ''
this.setState({
value
})
}}
options={optionTypes}
>
</SelectionView>
_scrollIntoView = (ref) => {
if (this.scroll) this.scroll.scrollIntoView(ref)
}
```
One observation, when I searched for scrollIntoView in lib folder, I could see this function declared in KeyboardAwareHOC
Hi,
The scrollIntoView function is not passed down to the scroll container, so it is not possible to call it (at least according to the documentation)
This PR fixes the issue: https://github.com/APSL/react-native-keyboard-aware-scroll-view/pull/258
hi @sebasgarcep
I've seen your math implementation and it almost work fine for my usecase:
const top = childLayout.y - parentLayout.y + this._contentOffset
The problem is that the view you call scrollIntoView with, will be put at the top of the scrollview. IMHO this is not the behavior of web:
1) If view is above the scroll area, then make the view appear at the top of the scrollview (align view top border with scrollview top border)
2) If view is under the scroll area, then make the view appear at the bottom of the scrollview (align view bottom border with scrollview bottom border)
Currently, it seems in all cases I have this behavior: align view top border with scrollview top border.
Do you know if it's possible to add support for the 2nd rule, so that behavior is closer to web behavior?
So I've been able to provide a better default implementation, maybe you can review it @sebasgarcep ?
https://github.com/APSL/react-native-keyboard-aware-scroll-view/pull/260
scrollintoview auto scroll to top in android!
Most helpful comment
This is what I've got:
And to use this method:
I haven't tested all of this but I believe it is correct and the
CustomScrollViewis copy-pasted from what we have in production. We are using React v16.2.0 and the React Native that comes with Expo v24.Inspired by this method from the DOM: https://developer.mozilla.org/es/docs/Web/API/Element/scrollIntoView