Skip to content

Commit 5be434e

Browse files
sebasgarcepalvaromb
authored andcommitted
Implements Scroll Into View (APSL#236)
* Implements Scroll Into View * fix linting issues and incorrect implementation
1 parent 58a1970 commit 5be434e

File tree

2 files changed

+72
-2
lines changed

2 files changed

+72
-2
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ Use `innerRef` to get the component reference and use `this.scrollRef.props` to
142142
| `getScrollResponder` | `void` | Get `ScrollResponder` |
143143
| `scrollToPosition` | `x: number, y: number, animated: bool = true` | Scroll to specific position with or without animation. |
144144
| `scrollToEnd` | `animated?: bool = true` | Scroll to end with or without animation. |
145+
| `scrollIntoView` | `element: React.Element<*>, options: { getScrollPosition: ?(parentLayout, childLayout, contentOffset) => { x: number, y: number, animated: boolean } }` | Scrolls an element inside a KeyboardAwareScrollView into view. |
145146

146147
### Using high order component
147148
Enabling any component to be keyboard-aware is very easy. Take a look at the code of `KeyboardAwareListView`:

lib/KeyboardAwareHOC.js

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ import ReactNative, {
66
Keyboard,
77
Platform,
88
UIManager,
9-
TextInput
9+
TextInput,
10+
findNodeHandle
1011
} from 'react-native'
1112
import { isIphoneX } from 'react-native-iphone-x-helper'
1213

@@ -36,6 +37,32 @@ export type KeyboardAwareHOCState = {
3637
keyboardSpace: number
3738
}
3839

40+
export type ElementLayout = {
41+
x: number,
42+
y: number,
43+
width: number,
44+
height: number
45+
}
46+
47+
export type ContentOffset = {
48+
x: number,
49+
y: number
50+
}
51+
52+
export type ScrollPosition = {
53+
x: number,
54+
y: number,
55+
animated: boolean
56+
}
57+
58+
export type ScrollIntoViewOptions = ?{
59+
getScrollPosition?: (
60+
parentLayout: ElementLayout,
61+
childLayout: ElementLayout,
62+
contentOffset: ContentOffset
63+
) => ScrollPosition
64+
}
65+
3966
function listenToKeyboardEvents(ScrollableComponent: React$Component) {
4067
return class extends React.Component<
4168
KeyboardAwareHOCProps,
@@ -44,7 +71,7 @@ function listenToKeyboardEvents(ScrollableComponent: React$Component) {
4471
_rnkasv_keyboardView: any
4572
keyboardWillShowEvent: ?Function
4673
keyboardWillHideEvent: ?Function
47-
position: { x: number, y: number }
74+
position: ContentOffset
4875
defaultResetScrollToCoords: ?{ x: number, y: number }
4976
resetCoords: ?{ x: number, y: number }
5077
mountedComponent: boolean
@@ -180,6 +207,48 @@ function listenToKeyboardEvents(ScrollableComponent: React$Component) {
180207
}, keyboardOpeningTime)
181208
}
182209

210+
scrollIntoView = async (
211+
element: React.Element<*>,
212+
options: ScrollIntoViewOptions = {}
213+
) => {
214+
if (!this._rnkasv_keyboardView || !element) {
215+
return
216+
}
217+
218+
const [
219+
parentLayout,
220+
childLayout
221+
] = await Promise.all([
222+
this._measureElement(this._rnkasv_keyboardView),
223+
this._measureElement(element)
224+
])
225+
226+
const getScrollPosition = options.getScrollPosition || this._defaultGetScrollPosition
227+
const { x, y, animated } = getScrollPosition(parentLayout, childLayout, this.position)
228+
this.scrollToPosition(x, y, animated)
229+
}
230+
231+
_defaultGetScrollPosition = (
232+
parentLayout: ElementLayout,
233+
childLayout: ElementLayout,
234+
contentOffset: ContentOffset
235+
): ScrollPosition => {
236+
return {
237+
x: 0,
238+
y: Math.max(0, childLayout.y - parentLayout.y + contentOffset.y),
239+
animated: true,
240+
}
241+
}
242+
243+
_measureElement = (element: React.Element<*>): Promise<ElementLayout> => {
244+
const node = findNodeHandle(element)
245+
return new Promise((resolve: (ElementLayout) => void) => {
246+
UIManager.measureInWindow(node, (x: number, y: number, width: number, height: number) => {
247+
resolve({ x, y, width, height })
248+
})
249+
})
250+
}
251+
183252
// Keyboard actions
184253
_updateKeyboardSpace = (frames: Object) => {
185254
// Automatically scroll to focused TextInput

0 commit comments

Comments
 (0)