Skip to content

Commit f6fffbc

Browse files
authored
Merge pull request #2 from iway1/1/easing-prop
Added easing prop
2 parents be9b60b + 5fa0d78 commit f6fffbc

File tree

8 files changed

+86
-78
lines changed

8 files changed

+86
-78
lines changed

App.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view
88
import KeyboardAvoiderScrollSection from './package/src/components/KeyboardAvoiderScrollSection';
99
import ReactNativeExample, { ReactNativeFixedExample } from './examples/react-native';
1010
import { textInputStyle } from './examples/styles';
11+
import { Easing } from 'react-native-reanimated';
1112

1213
const inputStyle: ViewStyle = {
1314
padding: 50,

README.md

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -276,28 +276,34 @@ For developer convenience, this repo is a React Native project. You can just pul
276276

277277
## Props
278278

279+
### Common props
280+
All of the components support the following props:
281+
282+
| **Props** | **Type** | **Description** | **Default** |
283+
|-----------------|-------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------|
284+
| animationTime | number | Time to move the view out of the way when the keyboard opens. | 150 |
285+
| animationEasing | Animated.EasingFunction | Easing function to use for both opening and closing animation.<br>Opening animation will use `Easing.out(animationEasing)`, while closing animation<br>will use `Easing.in(animationEasing)`. | Easing.quad |
286+
| extraSpace | number | How much space there should be between the keyboard avoiding element and the keyboard. | 20 |
287+
279288
### `KeyboardAvoiderView` Props
280-
All `View` props will be passed. Additionally, the following props can be passed:
289+
Supports all React Native `View` props as well as all [common props](#common-keyboardavoider-props).
290+
291+
Additionally, it supports the following props
292+
293+
| **Props** | **Type** | **Description** | **Default** |
294+
|---------------|---------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------|
295+
| avoidMode | 'whole-view'<br>'focused-input' | Which avoid mode to use.<br>'whole-view' will move the entire view out of the way.<br>'focused-input' will move just enough to show the input plus the extra space. | 'whole-view' |
296+
| enableAndroid | boolean | Enable keyboard avoiding on Android. | true |
281297

282-
| **Prop** | **Type** | **Description** | **Default** |
283-
|---------------|---------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------|
284-
| animationTime | number | Time to move the view out of the way when the keyboard opens. | 150 |
285-
| avoidMode | 'whole-view'<br>'focused-input' | Which avoid mode to use. <br>'whole-view' will move the entire `KeyboardAvoidingView` out of the way.<br>'focused-input' will only show the focused input. | 'whole-view' |
286-
| enableAndroid | boolean | Enable keyboard avoiding on android. | true |
287-
| extraSpace | number | How much space there should be between the keyboard avoiding element and the keyboard. | 20 |
288298

289299
### `KeyboardAvoiderScrollView` Props
290-
All `ScrollView` props can be passed. Additionally, the following props can be passed:
300+
Supports all React Native `ScrollView` props as well as all [common props](#common-keyboardavoider-props).
301+
302+
Additionally, it supports the following props
291303

292304
| **Props** | **Type** | **Description** | **Default** |
293305
|-----------------|--------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------|
294-
| extraSpace | number | How much space there should be between the keyboard avoiding element and the keyboard. | 20 |
295-
| animationTime | number | Time to move the view out of the way when the keyboard opens. | 150 |
296-
| iosHideBehavior | 'stay'<br>'revert' | What to do when the keyboard hides on iOS.<br>'stay' makes it where the scrollview stays where it is when the keyboard closes.<br>'revert' makes it where the scrollview returns to its original position. | 'stay' |
306+
| iosHideBehavior | 'stay'<br>'revert' | Behavior when the keyboard hides on iOS.<br>'stay' makes it where the scroll view stays where it is when the keyboard closes.<br>'revert' makes it where the scroll view returns to its original position. | 'stay' |
297307

298308
### `KeyboardAvoiderInsets` Props
299-
300-
| **Props** | **Type** | **Description** | **Default** |
301-
|---------------|----------|----------------------------------------------------------------------------------------|-------------|
302-
| extraSpace | number | How much space there should be between the keyboard avoiding element and the keyboard. | 20 |
303-
| animationTime | number | Time to move the view out of the way when the keyboard opens. | 150 |
309+
Supports all [common props](#common-keyboardavoider-props).

package/src/components/KeyboardAvoiderInsets.tsx

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,16 @@
11
import React from "react";
22
import { useRef } from "react";
33
import { Platform } from "react-native";
4-
import Animated, { useAnimatedStyle, useSharedValue, withTiming } from "react-native-reanimated";
5-
import { DEFAULT_ANIMATION_TIME, DEFAULT_EXTRA_SPACE } from "../defaults";
4+
import Animated, { EasingFn, useAnimatedStyle, useSharedValue, withTiming } from "react-native-reanimated";
65
import { useKeyboardHandlers } from "../hooks";
76
import { calcAndroidSystemPan, closeAnimation, measureFocusedInputBottomY, openAnimation } from "../utilities";
7+
import { CommonProps, defaultCommonProps } from "./common-props";
88

99
export default function KeyboardAvoiderInsets({
10-
animationTime = DEFAULT_ANIMATION_TIME,
11-
extraSpace = DEFAULT_EXTRA_SPACE,
12-
}: {
13-
/**
14-
* Duration of the keyboard avoiding animation.
15-
*/
16-
animationTime?: number,
17-
/**
18-
* Extra space between the keyboard avoiding element and the keyboard.
19-
*/
20-
extraSpace?: number,
21-
}) {
10+
animationEasing=defaultCommonProps.animationEasing,
11+
animationTime=defaultCommonProps.animationTime,
12+
extraSpace=defaultCommonProps.extraSpace
13+
}:CommonProps) {
2214
const heightAnimatedValue = useSharedValue<number>(0);
2315
const animatedRef = useRef<Animated.View | null>(null);
2416

@@ -31,30 +23,33 @@ export default function KeyboardAvoiderInsets({
3123
useKeyboardHandlers({
3224
showHandler: (e) => {
3325
if (Platform.OS == 'android') {
34-
measureFocusedInputBottomY((inputBottomY)=>{
26+
measureFocusedInputBottomY((inputBottomY) => {
3527
const systemPan = calcAndroidSystemPan({
3628
inputBottomY,
3729
keyboardEndY: e.endCoordinates.screenY,
3830
})
3931
animatedRef.current?.measure((x, y, width, height, pageX, pageY) => {
4032
const delta = Math.max(0, (pageY + extraSpace) - e.endCoordinates.screenY - systemPan);
4133
if (delta) {
42-
heightAnimatedValue.value = withTiming(delta, openAnimation(animationTime))
34+
heightAnimatedValue.value = withTiming(delta, {
35+
easing: animationEasing,
36+
duration: animationTime
37+
})
4338
}
4439
})
4540
})
4641
} else {
4742
animatedRef.current?.measure((x, y, width, height, pageX, pageY) => {
4843
const delta = Math.max(0, (pageY + extraSpace) - e.endCoordinates.screenY);
4944
if (delta) {
50-
heightAnimatedValue.value = withTiming(delta, openAnimation(animationTime))
45+
heightAnimatedValue.value = withTiming(delta, openAnimation(animationTime, animationEasing))
5146
}
5247
})
5348
}
5449

5550
},
5651
hideHandler: () => {
57-
heightAnimatedValue.value = withTiming(0, closeAnimation(animationTime))
52+
heightAnimatedValue.value = withTiming(0, closeAnimation(animationTime, animationEasing))
5853
}
5954
})
6055

package/src/components/KeyboardAvoiderScrollView.tsx

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,16 @@
11
import React, { createContext, useContext, useMemo, useRef, useState } from "react";
22
import { KeyboardEventListener, NativeScrollEvent, NativeSyntheticEvent, Platform, ScrollViewProps, View, ScrollView } from "react-native";
3-
import Animated, { Easing, Layout, scrollTo, useAnimatedRef, useAnimatedStyle, useDerivedValue, useSharedValue, withTiming } from "react-native-reanimated";
4-
import { DEFAULT_ANIMATION_TIME, DEFAULT_EXTRA_SPACE } from "../defaults";
3+
import Animated, { scrollTo, useAnimatedRef, useAnimatedStyle, useDerivedValue, useSharedValue, withTiming } from "react-native-reanimated";
54
import { useKeyboardHandlers } from "../hooks";
65
import { closeAnimation, measureFocusedInputBottomYAsync } from "../utilities";
6+
import { CommonProps, defaultCommonProps } from "./common-props";
77

88
const ScrollContext = createContext<{
99
registerView: ({view, id,}:{view: View, id: string}) => void,
1010
unregisterView: (id: string)=>void,
1111
} | null>(null);
1212

13-
interface Props extends ScrollViewProps {
14-
/**
15-
* Extra space between the keyboard and the keyboard avoiding element.
16-
* Defaults to 20.
17-
*/
18-
extraSpace?: number,
19-
20-
/**
21-
* Duration of the keyboard avoiding animation.
22-
*/
23-
animationTime?: number,
24-
13+
type Props = ScrollViewProps & CommonProps & {
2514
/**
2615
* What to do when the keyboard hides on iOS.
2716
* @option 'stay' - *Default* scroll view will not move when the keyboard hides (it will stay where it is.)
@@ -39,8 +28,9 @@ async function measureView(view: View) {
3928
}
4029

4130
export default function KeyboardAvoiderScrollView({
42-
extraSpace = DEFAULT_EXTRA_SPACE,
43-
animationTime=DEFAULT_ANIMATION_TIME,
31+
animationEasing=defaultCommonProps.animationEasing,
32+
animationTime=defaultCommonProps.animationTime,
33+
extraSpace=defaultCommonProps.extraSpace,
4434
iosHideBehavior='stay',
4535
...props
4636
}: Props) {
@@ -105,7 +95,7 @@ export default function KeyboardAvoiderScrollView({
10595

10696
function handleKeyboardWillHide() {
10797
if(Platform.OS == 'android' || iosHideBehavior == 'revert') {
108-
yTranslate.value = withTiming(0, closeAnimation(animationTime))
98+
yTranslate.value = withTiming(0, closeAnimation(animationTime, animationEasing))
10999
return;
110100
}
111101
const scrollsToAdjustedForTranslate = currentScroll.current - yTranslate.value;
@@ -114,7 +104,7 @@ export default function KeyboardAvoiderScrollView({
114104
if(scrollsToAdjustedForTranslate >= scrollMax.current) {
115105
// In cases where there is no room to actually scroll the scroll view we just animate back to the
116106
// start position.
117-
yTranslate.value = withTiming(0, closeAnimation(animationTime))
107+
yTranslate.value = withTiming(0, closeAnimation(animationTime, animationEasing))
118108
return;
119109
}
120110

package/src/components/KeyboardAvoiderView.tsx

Lines changed: 12 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -13,31 +13,24 @@ import Animated, {
1313
useSharedValue,
1414
withTiming,
1515
} from 'react-native-reanimated'
16-
import { DEFAULT_ANIMATION_TIME, DEFAULT_EXTRA_SPACE } from '../defaults'
1716
import { useKeyboardHandlers } from '../hooks'
1817
import { closeAnimation, measureFocusedInputBottomY, openAnimation } from '../utilities'
18+
import { CommonProps, defaultCommonProps } from './common-props'
1919

2020
export type KeyboardAvoidMode = 'whole-view' | 'focused-input';
2121

2222
export default function KeyboardAvoiderView({
23+
animationEasing = defaultCommonProps.animationEasing,
24+
animationTime = defaultCommonProps.animationTime,
25+
extraSpace = defaultCommonProps.extraSpace,
2326
enableAndroid = true,
24-
animationTime = DEFAULT_ANIMATION_TIME,
25-
extraSpace = DEFAULT_EXTRA_SPACE,
2627
avoidMode = 'whole-view',
2728
...props
28-
}: ComponentProps<typeof Animated.View> & {
29+
}: ComponentProps<typeof Animated.View> & CommonProps & {
2930
/**
3031
* Enable on android. Defaults to true to ensure consistent behavior.
3132
*/
3233
enableAndroid?: boolean,
33-
/**
34-
* Sets the duration of the keyboard avoiding animation.
35-
*/
36-
animationTime?: number,
37-
/**
38-
* Extra space between the keyboard avoiding element and the keyboard.
39-
*/
40-
extraSpace?: number,
4134
/**
4235
* Sets the avoid mode. Defaults to 'whole-view'.
4336
* @option 'whole-view' - view moves to show the entire view when the keyboard is shown.
@@ -52,12 +45,12 @@ export default function KeyboardAvoiderView({
5245

5346
const handleKeyboardWillShow: KeyboardEventListener = (e) => {
5447
keyboardTopRef.current = e.endCoordinates.screenY
55-
48+
5649
if (Platform.OS == 'android') {
5750
measureFocusedInputBottomY((inputBottomY) => {
5851
const pannedBy = Math.max(inputBottomY - e.endCoordinates.screenY, 0);
59-
if(avoidMode=='focused-input') {
60-
setScrollToElementBottomY(inputBottomY-pannedBy)
52+
if (avoidMode == 'focused-input') {
53+
setScrollToElementBottomY(inputBottomY - pannedBy)
6154
return;
6255
}
6356
ref.current?.measure((x, y, w, viewHeight, px, viewPageY) => {
@@ -79,7 +72,7 @@ export default function KeyboardAvoiderView({
7972
})
8073
}
8174
}
82-
75+
8376
function handleKeyboardWillHide() {
8477
setScrollToElementBottomY(null)
8578
}
@@ -91,18 +84,18 @@ export default function KeyboardAvoiderView({
9184
}, [avoidMode, extraSpace, animationTime])
9285

9386
function pos(scrollTo: number) {
94-
return scrollTo - keyboardTopRef.current + DEFAULT_EXTRA_SPACE
87+
return scrollTo - keyboardTopRef.current + extraSpace
9588
}
9689

9790
useEffect(() => {
9891
if (scrollToElementBottomY === null) {
99-
animation.value = withTiming(0, closeAnimation(animationTime))
92+
animation.value = withTiming(0, closeAnimation(animationTime, animationEasing))
10093
return
10194
}
10295
const p = pos(scrollToElementBottomY);
10396
if (p <= 0) return
10497
if (animation.value !== p) {
105-
animation.value = withTiming(p, openAnimation(animationTime))
98+
animation.value = withTiming(p, openAnimation(animationTime, animationEasing))
10699
}
107100
}, [scrollToElementBottomY])
108101

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import Animated, { Easing } from "react-native-reanimated"
2+
3+
export type CommonProps = {
4+
/**
5+
* Duration of the keyboard avoiding animation.
6+
*/
7+
animationTime?: number,
8+
/**
9+
* Extra space between the keyboard avoiding element and the keyboard.
10+
*/
11+
extraSpace?: number,
12+
/**
13+
* Easing function to use. Can be any `react-native-reanimated` easing function. Defaults to Easing.quad.
14+
* Open animation will use Easing.out(animationEasing), close animation will use Easing.in(animationEasing).
15+
*/
16+
animationEasing?: Animated.EasingFunction
17+
}
18+
19+
export const defaultCommonProps = {
20+
animationTime: 150,
21+
animationEasing: Easing.quad,
22+
extraSpace: 20,
23+
}

package/src/defaults.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
export const DEFAULT_EXTRA_SPACE = 20
2-
export const DEFAULT_ANIMATION_TIME = 150
1+
import { Easing } from "react-native-reanimated"
2+

package/src/utilities.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { TextInput } from "react-native"
2-
import { Easing } from "react-native-reanimated";
2+
import Animated, { Easing } from "react-native-reanimated";
33

44
export async function measureFocusedInputBottomYAsync() {
55
return new Promise<number>(resolve=>{
@@ -36,16 +36,16 @@ export function calcAndroidSystemPan({
3636
return Math.max(0, delta);
3737
}
3838

39-
export function closeAnimation(duration: number) {
39+
export function closeAnimation(duration: number, easing: Animated.EasingFunction) {
4040
return {
4141
duration: duration + 50,
42-
easing: Easing.in(Easing.ease)
42+
easing: Easing.in(easing)
4343
}
4444
}
4545

46-
export function openAnimation(duration: number) {
46+
export function openAnimation(duration: number, easing: Animated.EasingFunction) {
4747
return {
4848
duration,
49-
easing: Easing.inOut(Easing.ease)
49+
easing: Easing.out(easing)
5050
}
5151
}

0 commit comments

Comments
 (0)