π React Native 리μ‘νΈ λ€μ΄ν°λΈ - Animation
@ μΊλ¬μ Carousel
π« Animation
μ λλ©μ΄μ μ UI μμκ° μμ©ν λ λͺ νν νΌλλ°±μ μ¬μ©μμκ² μ 곡νλ€.
리μ‘νΈ λ€μ΄ν°λΈκ° μ 곡νλ κΈ°λ₯μ 4κ°μ§λ‘ μμ½ν μ μλ€.
1
import {Animated, Easing, PanResponder, LayoutAnimation} from 'react-native'
π« νΉμ§
리μ‘νΈ λ€μ΄ν°λΈ μ λλ©μ΄μ μ λ κ°μ§ λͺ¨λλ‘ λμνλ€.
- μλ°μ€ν¬λ¦½νΈ μμ§ μ λλ©μ΄μ
- λ€μ΄ν°λΈ λͺ¨λ μ λλ©μ΄μ
λ€μ΄ν°λΈ λͺ¨λ μ λλ©μ΄μ μ μ¬μ©ν κ²μ κΆκ³ νλ€.
useNativeDriver μμ±μ ν΅ν΄ μ΄λ€ λͺ¨λλ‘ μ λλ©μ΄μ μ λμμν¬μ§ κ²°μ ν μ μλ€.
λ°λΌμ λ€μ΄ν°λΈ λͺ¨λ μ λλ©μ΄μ μ κΈ°λ°μΌλ‘ νλ, λΆκ°λ₯ν κ²λ€μ (fontSize, β¦) useNativeDriver μμ±μ μ΄μ©νμ¬ κ΅¬ννλ€.
π« Animatedκ° μ 곡νλ μ λλ©μ΄μ κΈ°λ₯
- μ λλ©μ΄μ
보κ°κ°
Value
- ValueXY
- λ¨μΌ μ λλ©μ΄μ
μ μ΄
timing()
- spring()
- decay()
- delay()
- loop()
- μ¬λ¬ κ°μ μ λλ©μ΄μ
ν΅ν© μ μ΄
- sequence()
- parallel()
- stagger()
- μ λλ©μ΄μ
μ°μ°
- add()
- substract()
- multiply()
- divide()
- modulo()
- diffClamp
- μ λλ©μ΄μ
μ΄λ²€νΈ
- event()
- μ λλ©μ΄μ
λμ μ»΄ν¬λνΈ
View
- Image
- Text
- ScrollView
- FlatList
- SectionList
𫧠Value ν΄λμ€
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
export class Value
{
constructor(value: number);
setValue(value: numbe): void;
// μ½λ°± ν¨μλ₯Ό ν΅ν΄ νμ¬ λ³΄κ° μ€μΈ κ°μ μ»μ μ μλ€.
// useEffectμμ add/remove νλ μ
addListener(callback: ValueListenderCallback): string;
removeListener(id: string): void;
removeAllListeners(): void;
// μ
λ ₯ λ³΄κ° κ°μ μλ‘μ΄ λ³΄κ°κ°μΌλ‘ λ°κΏ μ μλ€.
// i.e. μΆλ ₯μ 0 ~ 100, Red ~ Blue, 0deg ~ 360deg
interpolate(config: InterpolationConfigType): AnimatedInterpolation;
// animValue.interpolate({inputRange: [0, 1], outputRange: [0, 100]})
// animValue.interpolate({inputRange: [0, 1], outputRange: ['red', 'blue']})
// animValue.interpolate({inputRange: [0, 1], outputRange: ['0deg', '360deg']})
// animValue.interpolate({inputRange: [0, 0.7, 1], outputRange: [Colors.lightBlue900, Colors.lime500, Colors.pink500]})
// ~
}
type ValueListenerCallback = (stage: {value: number}) => void;
class AnimatedInterpolation
{
interpolate(config: InterpolationConfigType): AnimatedInterpolation;
}
// inputRangeλ₯Ό λ²μ΄λ κ°μ΄ λ°μνμ λ μ΄λ€ κ°μΌλ‘ outputRangeλ₯Ό λ§λ€μ§ κ²°μ νλ μμ±
// clamp : κ° λ¬΄μ
// extend : λ²μ λ΄ κ°μ κ³μ°ν 곡μμ λ²μ μΈ κ°μλ λκ°μ΄ μ μ©
// identity : μ΄λ€ 곡μλ μ μ©νμ§ μκ³ μ
λ ₯κ° κ·Έλλ‘ μΆλ ₯
type ExtrapolateType = 'extend' | 'identity' | 'clamp';
type InterpolationConfigType =
{
inputRange: number[];
outputRange: number[] | string[];
// Like Animated.timing
easing?: (input: number) => number;
};
π« λμ μ리
리μ‘νΈ λ€μ΄ν°λΈ μ λλ©μ΄μ μ CSS μ λλ©μ΄μ κ³Ό κ°μ κ°λ μ΄λ€.
CSS μ λλ©μ΄μ μ, transitionμ΄λ animate μ€νμΌ μμ±μ μ λλ©μ΄μ μ μ μ©νκ³ μΆμ λ€λ₯Έ μ€νμΌ μμ±κ°μ μ‘°μ νλ λ°©μμΌλ‘ λμνλ€.
리μ‘νΈ λ€μ΄ν°λΈ μ λλ©μ΄μ μ, style μμ±μ μ€μ νλ opacity, transform λ±μ μ€νμΌ μμ±μ 보κ°ν κ°μ μ μ₯νλ Animated.Value ν΄λμ€ κ°μ²΄(μΈμ€ν΄μ€)λ₯Ό μ€μ νλ λ°©μμΌλ‘ λμνλ€.
π« ꡬν
𫧠Animated.Value ν΄λμ€μ μΈμ€ν΄μ€ μμ±
Animated.Value ν΄λμ€μ μΈμ€ν΄μ€ μμ±μΌλ‘ μμν΄λ λμ§λ§,
리μ‘νΈ λ€μ΄ν°λΈ νμ useRef ν μ μ¬μ©νμ¬ Animated.Value ν΄λμ€μ μΈμ€ν΄μ€λ₯Ό μΊμνλ λ°©λ²μ κΆμ₯νλ€.
1
2
3
4
5
// O
const animValue = new Animated.Value(0)
// O (κΆμ₯)
const animValue = useRef(new Animated.Value(0)).current
useRefμ μ¬μ©νλ©΄, animValueλ₯Ό λ¨ ν λ²λ§ μμ±νκ³ μ¬λ λλ§ μ μ¬μ¬μ©νλ€.
𫧠Animated.Value ν΄λμ€μ μΈμ€ν΄μ€ μ μ©
Animated.Value ν΄λμ€μ μΈμ€ν΄μ€λ₯Ό μ»΄ν¬λνΈμ μ€νμΌ μμ±μ μ μ©νλ€.
1
const someViewAnimStyle= {opacity: animValue}
opacity μμ±μ νμ μ΄ numberκ° μλλΌ Animated.Value νμ μ΄λ―λ‘ View κ°μ μ»΄ν¬λνΈλ μ΄λ₯Ό ν΄μν μ μλ€.
λλ¬Έμ Animated.View κ°μ μ»΄ν¬λνΈλ₯Ό μ΄μ©νμ¬ μ€νμΌ μμ± μ€μ κ°μ΄ Animated.Value νμ κ°μ²΄μΈ μ€νμΌ μμ±μ μ²λ¦¬ν μ μκ² νλ€.
1
<Animated.View style={[styles.someView, someViewAnimStyle]}>
𫧠μ λλ©μ΄μ μ¬μ
μ λλ©μ΄μ μ μ¬μμν€λ €λ©΄ onPress λ±μμ μ½λλ₯Ό μ€νν΄μΌ νλ€.
1
2
3
4
const onPress = () =>
{
Animated.timing(animValue, {toValue:1, uesNativeDriver: true, duration: 1000}).start()
}
𫧠useRef ν κ³Ό MutableRefObject νμ
useRef ν
μ RefObject<T>
λλ MutableRefObject<T>
μ λ°νν μ μλ€.
1
function useRef<T>(initialValue: T): MutableRefObject<T>
MutableRefObject μ λ€λ¦ νμ μλ λ€μ RefObject νμ μ²λΌ currentλΌλ μμ±μ΄ μλ€. λ€λ§ currentμ νμ μ T | nullμ΄ μλλΌ Tμ΄λ€. μ¦, currenλ nullμ΄ λ μ μλ€. |
1
2
3
4
interface MutableRefObject<T>
{
current: T;
}
κ·Έλ¬λ―λ‘ animValueλ nullμ΄ λ μ μμΌλ©° λ³νμ§λ μλλ€. λλ¬Έμ κ΅³μ΄ animValueλ₯Ό useMemo, useCallbackμ μμ‘΄μ± λͺ©λ‘μ μΆκ°ν νμκ° μλ€.
animValueκ° μλλΌ, animValue λ΄λΆμ value μμ±μ κ°μ΄ 보κ°μ μν΄ 0~1λ‘ λ³νλ κ²μ΄λ€.
1
const animValue = useRef(new Animted.Value(0)).current;
𫧠Animated.Viewμ Animated.createAnimatedComponent ν¨μ
Animated.createAnimatedComponent ν¨μλ λ€λ₯Έ μ»΄ν¬λνΈλ₯Ό 맀κ°λ³μλ‘ μ λ ₯λ°μ Animated.Value νμ κ°μ²΄λ₯Ό μ²λ¦¬ν μ μλ κΈ°λ₯μ κ°μ§λ μλ‘μ΄ μ»΄ν¬λνΈλ₯Ό λ§λ λ€.
μμ£Ό μ°μ΄λ View, Text, Imageλ κ΅³μ΄ μμ±νμ§ μμλ λ°λ‘ μ¬μ©ν μ μλλ‘ μ»΄ν¬λνΈλ₯Ό μ 곡νλ€.
1
2
3
4
5
6
7
8
9
10
11
type AnimatedComponent = Animated.createAnimatedComponent
export function createAnimatedComponent<T>(component: T): AnimatedComponent<T>;
Animated.View
// Animated.createAnimatedComponent(View)
Animated.Text
// Animated.createAnimatedComponent(Text)
Animated.Image
// Animated.createAnimatedComponent(Image)
𫧠Animated.timing
Animated.timingμ valueμ configλ₯Ό 맀κ°λ³μλ‘ λ°μ Animated.CompositeAnimation νμ κ°μ²΄λ₯Ό λ°ννλ ν¨μμ΄λ€.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
export const Animated.timing:
(
value: Animated.Value | Animated.ValueXY,
config: Animated.TimingAnimationConfig
) => Animated.ComposteAnimation;
// Animated.TimingAnimationConfig
interface AnimationConfig
{
useNativeDriver: boolean;
}
interface TimingAnimationConfig extends AnimationConfig
{
toValue: number | Animated.Value // new Animated.Value(μμκ°)μ λκ° μ€μ
duration?: number // μ λλ©μ΄μ
μ§ν μκ° (millisecond)
delay?: number // μ λλ©μ΄μ
μ§ν μ λκΈ° μκ°
easing?: (value: number) => nuber; // Easingμ΄ μ¬μ©νλ λ³΄κ° ν¨μ
}
// Easing
export type EasingFunction = (value: number) => number;
export interface Easing
{
linear: EasingFunction;
ease: EasingFunction;
// ~
}
// CompositeAnimation
export interface CompositeAnimation
{
start: (callback?: EndCallback) => void;
// ~
}
type EndResult = {finished: boolean};
type EndCallback = (result: EndResult) => void;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// i.e.
Animated.timing
(
// λμ
animValue,
// μ λλ©μ΄μ
{
useNativeDriver: true,
toValue: show ? 0 : 1,
duration: 1000,
easing: Easing.bounce
}
).start(
(result: {finished: boolean}) => console.log(result)
)
// result 맀κ°λ³μλ νμ {finished: true} μ΄λ―λ‘ () => console.log('animation end') κ°μ΄ ꡬνν΄λ μ’λ€
𫧠ransform Animation
@ μμ μ€ μλ΅
𫧠Animated μ°μ° κ΄λ ¨ ν¨μ
1
2
3
4
5
6
7
8
type Value = Animated.Value
export function add(a: Value, b: Value): Animated.AnimatedInterpolation // +
export function substract(a: Value, b: Value): Animated.AnimatedInterpolation // -
export function multiply(a: Value, b: Value): Animated.AnimatedInterpolation // *
export function divide(a: Value, b: Value): Animated.AnimatedInterpolation // /
export function modulo(a: Value, b: Value): Animated.AnimatedInterpolation // %
// 맀κ°λ³μκ° numberκ° μλ Animated.Valueμμ μ£Όμ