0
# Animation
1
2
React Native's Animated API adapted for web with full support for declarative animations, timing functions, spring physics, and composition utilities for building complex animated UIs.
3
4
## Animated
5
6
The main Animated API providing declarative animation capabilities with configurable transforms, value management, and timing control for building fluid, maintainable animations.
7
8
```javascript { .api }
9
const Animated: {
10
// Value Classes
11
Value: typeof AnimatedValue;
12
ValueXY: typeof AnimatedValueXY;
13
Color: typeof AnimatedColor;
14
15
// Animation Functions
16
timing: (value: AnimatedValue | AnimatedValueXY | AnimatedColor, config: TimingAnimationConfig) => CompositeAnimation;
17
spring: (value: AnimatedValue | AnimatedValueXY | AnimatedColor, config: SpringAnimationConfig) => CompositeAnimation;
18
decay: (value: AnimatedValue | AnimatedValueXY | AnimatedColor, config: DecayAnimationConfig) => CompositeAnimation;
19
20
// Composition Functions
21
parallel: (animations: CompositeAnimation[], config?: ParallelConfig) => CompositeAnimation;
22
sequence: (animations: CompositeAnimation[]) => CompositeAnimation;
23
stagger: (time: number, animations: CompositeAnimation[]) => CompositeAnimation;
24
delay: (time: number) => CompositeAnimation;
25
loop: (animation: CompositeAnimation, config?: LoopAnimationConfig) => CompositeAnimation;
26
27
// Math Operations
28
add: (a: AnimatedNode | number, b: AnimatedNode | number) => AnimatedAddition;
29
subtract: (a: AnimatedNode | number, b: AnimatedNode | number) => AnimatedSubtraction;
30
multiply: (a: AnimatedNode | number, b: AnimatedNode | number) => AnimatedMultiplication;
31
divide: (a: AnimatedNode | number, b: AnimatedNode | number) => AnimatedDivision;
32
modulo: (a: AnimatedNode, modulus: number) => AnimatedModulo;
33
diffClamp: (a: AnimatedNode, min: number, max: number) => AnimatedDiffClamp;
34
35
// Event Handling
36
event: (argMapping: Mapping[], config: EventConfig) => Function;
37
forkEvent: (event: AnimatedEvent | Function, listener: Function) => AnimatedEvent | Function;
38
unforkEvent: (event: AnimatedEvent | Function, listener: Function) => void;
39
40
// Components
41
View: typeof AnimatedView;
42
Text: typeof AnimatedText;
43
Image: typeof AnimatedImage;
44
ScrollView: typeof AnimatedScrollView;
45
FlatList: typeof AnimatedFlatList;
46
SectionList: typeof AnimatedSectionList;
47
48
// Utilities
49
createAnimatedComponent: <T>(Component: T) => T;
50
attachNativeEvent: (viewRef: any, eventName: string, argMapping: Mapping[]) => void;
51
52
// Type Exports
53
Node: typeof AnimatedNode;
54
Interpolation: typeof AnimatedInterpolation;
55
Event: typeof AnimatedEvent;
56
};
57
```
58
59
## Easing
60
61
Comprehensive easing functions library providing mathematically accurate timing curves for animations. Includes predefined animations, standard mathematical functions, and helper functions for creating custom easing behaviors.
62
63
```javascript { .api }
64
const Easing: {
65
// Predefined animations
66
ease: (t: number) => number;
67
bounce: (t: number) => number;
68
back: (s?: number) => (t: number) => number;
69
elastic: (bounciness?: number) => (t: number) => number;
70
71
// Standard functions
72
linear: (t: number) => number;
73
quad: (t: number) => number;
74
cubic: (t: number) => number;
75
poly: (n: number) => (t: number) => number;
76
77
// Mathematical functions
78
sin: (t: number) => number;
79
circle: (t: number) => number;
80
exp: (t: number) => number;
81
bezier: (x1: number, y1: number, x2: number, y2: number) => (t: number) => number;
82
83
// Stepping functions
84
step0: (n: number) => number;
85
step1: (n: number) => number;
86
87
// Direction helpers
88
in: (easing: (t: number) => number) => (t: number) => number;
89
out: (easing: (t: number) => number) => (t: number) => number;
90
inOut: (easing: (t: number) => number) => (t: number) => number;
91
};
92
```
93
94
**Web Implementation:**
95
All easing functions are implemented using pure JavaScript mathematical functions, providing consistent behavior across all platforms and browsers.
96
97
### Predefined Animations
98
99
```javascript { .api }
100
// Simple inertial animation, similar to CSS ease
101
Easing.ease(t: number): number
102
103
// Bouncing animation with multiple bounces
104
Easing.bounce(t: number): number
105
106
// Animation that goes slightly back before moving forward
107
Easing.back(s?: number): (t: number) => number
108
109
// Spring-like elastic animation with configurable bounciness
110
Easing.elastic(bounciness?: number): (t: number) => number
111
```
112
113
### Standard Mathematical Functions
114
115
```javascript { .api }
116
// Linear timing (no easing)
117
Easing.linear(t: number): number
118
119
// Quadratic timing (t²)
120
Easing.quad(t: number): number
121
122
// Cubic timing (t³)
123
Easing.cubic(t: number): number
124
125
// Power timing (t^n)
126
Easing.poly(n: number): (t: number) => number
127
```
128
129
### Advanced Mathematical Functions
130
131
```javascript { .api }
132
// Sinusoidal timing
133
Easing.sin(t: number): number
134
135
// Circular timing
136
Easing.circle(t: number): number
137
138
// Exponential timing
139
Easing.exp(t: number): number
140
141
// Cubic Bézier curve (like CSS transition-timing-function)
142
Easing.bezier(x1: number, y1: number, x2: number, y2: number): (t: number) => number
143
```
144
145
### Direction Helpers
146
147
```javascript { .api }
148
// Run easing function forwards (identity function)
149
Easing.in(easing: (t: number) => number): (t: number) => number
150
151
// Run easing function backwards
152
Easing.out(easing: (t: number) => number): (t: number) => number
153
154
// Make easing function symmetrical (ease in for first half, ease out for second half)
155
Easing.inOut(easing: (t: number) => number): (t: number) => number
156
```
157
158
**Usage:**
159
```javascript
160
import { Animated, Easing } from "react-native-web";
161
162
function EasingExample() {
163
const fadeAnim = new Animated.Value(0);
164
const slideAnim = new Animated.Value(-100);
165
166
const startAnimation = () => {
167
Animated.parallel([
168
// Fade in with custom cubic bezier
169
Animated.timing(fadeAnim, {
170
toValue: 1,
171
duration: 500,
172
easing: Easing.bezier(0.25, 0.1, 0.25, 1), // CSS ease
173
useNativeDriver: false,
174
}),
175
176
// Slide in with elastic bounce
177
Animated.timing(slideAnim, {
178
toValue: 0,
179
duration: 800,
180
easing: Easing.elastic(1.5),
181
useNativeDriver: false,
182
}),
183
184
// Complex custom easing using helpers
185
Animated.timing(rotateAnim, {
186
toValue: 360,
187
duration: 1000,
188
easing: Easing.inOut(Easing.back(2)),
189
useNativeDriver: false,
190
}),
191
]).start();
192
};
193
194
return (
195
<Animated.View
196
style={{
197
opacity: fadeAnim,
198
transform: [
199
{ translateX: slideAnim },
200
{ rotate: rotateAnim.interpolate({
201
inputRange: [0, 360],
202
outputRange: ['0deg', '360deg']
203
})}
204
],
205
}}
206
>
207
<Text>Animated with custom easing!</Text>
208
</Animated.View>
209
);
210
}
211
212
// Compare different easing functions
213
const easingComparison = {
214
linear: Easing.linear,
215
ease: Easing.ease,
216
easeOut: Easing.out(Easing.quad),
217
easeInOut: Easing.inOut(Easing.cubic),
218
bounce: Easing.bounce,
219
elastic: Easing.elastic(1),
220
back: Easing.back(),
221
};
222
```
223
224
## Value Classes
225
226
### Animated.Value
227
Standard animated value class for driving single-property animations.
228
229
```javascript { .api }
230
class AnimatedValue extends AnimatedNode {
231
constructor(value: number, config?: AnimatedValueConfig): AnimatedValue;
232
setValue(value: number): void;
233
setOffset(offset: number): void;
234
flattenOffset(): void;
235
extractOffset(): void;
236
addListener(callback: ValueListenerCallback): string;
237
removeListener(id: string): void;
238
removeAllListeners(): void;
239
stopAnimation(callback?: (value: number) => void): void;
240
resetAnimation(callback?: (value: number) => void): void;
241
interpolate(config: InterpolationConfigType): AnimatedInterpolation;
242
animate(animation: Animation, callback?: EndCallback): void;
243
stopTracking(): void;
244
track(tracking: AnimatedTracking): void;
245
}
246
```
247
248
**Usage:**
249
```javascript
250
import { Animated, View } from "react-native-web";
251
252
function FadeInView({ children }) {
253
const fadeAnim = new Animated.Value(0);
254
255
React.useEffect(() => {
256
Animated.timing(fadeAnim, {
257
toValue: 1,
258
duration: 1000,
259
useNativeDriver: false
260
}).start();
261
}, [fadeAnim]);
262
263
return (
264
<Animated.View style={{ opacity: fadeAnim }}>
265
{children}
266
</Animated.View>
267
);
268
}
269
270
// Advanced value manipulation
271
function ComplexAnimation() {
272
const translateX = new Animated.Value(0);
273
const scale = new Animated.Value(1);
274
275
// Set initial value
276
translateX.setValue(50);
277
278
// Add offset (current value becomes offset + value)
279
translateX.setOffset(100);
280
translateX.setValue(0); // Now animates from 100
281
282
// Listen to value changes
283
const listenerId = translateX.addListener(({ value }) => {
284
console.log(`TranslateX: ${value}`);
285
});
286
287
// Interpolate for different properties
288
const backgroundColor = translateX.interpolate({
289
inputRange: [0, 100],
290
outputRange: ['rgba(255,0,0,0.5)', 'rgba(0,0,255,0.5)'],
291
extrapolate: 'clamp'
292
});
293
294
return (
295
<Animated.View
296
style={{
297
transform: [
298
{ translateX },
299
{ scale }
300
],
301
backgroundColor
302
}}
303
/>
304
);
305
}
306
```
307
308
### Animated.ValueXY
309
2D animated value class for driving pan gestures and multi-dimensional animations.
310
311
```javascript { .api }
312
class AnimatedValueXY extends AnimatedNode {
313
x: AnimatedValue;
314
y: AnimatedValue;
315
316
constructor(valueIn?: { x: number | AnimatedValue; y: number | AnimatedValue }, config?: AnimatedValueConfig): AnimatedValueXY;
317
setValue(value: { x: number; y: number }): void;
318
setOffset(offset: { x: number; y: number }): void;
319
flattenOffset(): void;
320
extractOffset(): void;
321
stopAnimation(callback?: (value: { x: number; y: number }) => void): void;
322
resetAnimation(callback?: (value: { x: number; y: number }) => void): void;
323
addListener(callback: ValueXYListenerCallback): string;
324
removeListener(id: string): void;
325
removeAllListeners(): void;
326
getLayout(): { left: AnimatedValue; top: AnimatedValue };
327
getTranslateTransform(): [{ translateX: AnimatedValue }, { translateY: AnimatedValue }];
328
}
329
```
330
331
**Usage:**
332
```javascript
333
// Pan gesture with ValueXY
334
function DraggableBox() {
335
const pan = new Animated.ValueXY();
336
const panGesture = PanGestureHandler.create({
337
onGestureEvent: Animated.event(
338
[{ nativeEvent: { translationX: pan.x, translationY: pan.y } }],
339
{ useNativeDriver: false }
340
),
341
onHandlerStateChange: (event) => {
342
if (event.nativeEvent.oldState === State.ACTIVE) {
343
// Snap back to center
344
Animated.spring(pan, {
345
toValue: { x: 0, y: 0 },
346
useNativeDriver: false
347
}).start();
348
}
349
}
350
});
351
352
return (
353
<PanGestureHandler {...panGesture}>
354
<Animated.View
355
style={{
356
transform: pan.getTranslateTransform(),
357
width: 100,
358
height: 100,
359
backgroundColor: 'blue'
360
}}
361
/>
362
</PanGestureHandler>
363
);
364
}
365
366
// Complex 2D animation
367
function Orbit() {
368
const position = new Animated.ValueXY({ x: 0, y: 0 });
369
const angle = new Animated.Value(0);
370
371
React.useEffect(() => {
372
const animateOrbit = () => {
373
const radius = 50;
374
angle.setValue(0);
375
376
Animated.timing(angle, {
377
toValue: 2 * Math.PI,
378
duration: 2000,
379
useNativeDriver: false
380
}).start(() => animateOrbit());
381
};
382
383
animateOrbit();
384
}, []);
385
386
// Convert polar to cartesian coordinates
387
const x = Animated.multiply(
388
Animated.add(Math.cos, angle),
389
radius
390
);
391
const y = Animated.multiply(
392
Animated.add(Math.sin, angle),
393
radius
394
);
395
396
return (
397
<Animated.View
398
style={{
399
position: 'absolute',
400
left: x,
401
top: y,
402
width: 20,
403
height: 20,
404
backgroundColor: 'red',
405
borderRadius: 10
406
}}
407
/>
408
);
409
}
410
```
411
412
### Animated.Color
413
Animated value class for color animations with RGBA channel support.
414
415
```javascript { .api }
416
class AnimatedColor extends AnimatedNode {
417
r: AnimatedValue;
418
g: AnimatedValue;
419
b: AnimatedValue;
420
a: AnimatedValue;
421
422
constructor(valueIn?: string | { r: number; g: number; b: number; a: number }): AnimatedColor;
423
setValue(value: string): void;
424
}
425
```
426
427
## Animation Functions
428
429
### timing()
430
Animates a value along a timed easing curve with configurable duration and easing function.
431
432
```javascript { .api }
433
Animated.timing(
434
value: AnimatedValue | AnimatedValueXY | AnimatedColor,
435
config: {
436
toValue: number | AnimatedValue | { x: number; y: number } | string;
437
duration?: number; // default: 500
438
easing?: EasingFunction; // default: Easing.inOut(Easing.ease)
439
delay?: number; // default: 0
440
useNativeDriver?: boolean; // default: false
441
onComplete?: (result: EndResult) => void;
442
}
443
): CompositeAnimation
444
```
445
446
**Usage:**
447
```javascript
448
// Basic timing animation
449
const opacity = new Animated.Value(0);
450
451
Animated.timing(opacity, {
452
toValue: 1,
453
duration: 300,
454
useNativeDriver: false
455
}).start();
456
457
// Custom easing functions
458
import { Easing } from "react-native-web";
459
460
Animated.timing(opacity, {
461
toValue: 1,
462
duration: 500,
463
easing: Easing.bezier(0.25, 0.1, 0.25, 1), // Custom bezier
464
useNativeDriver: false
465
}).start();
466
467
// Sequential timing with callbacks
468
function SequentialAnimation() {
469
const slideIn = new Animated.Value(-100);
470
const fadeIn = new Animated.Value(0);
471
472
const animateIn = () => {
473
Animated.timing(slideIn, {
474
toValue: 0,
475
duration: 300,
476
easing: Easing.out(Easing.back(1.7)),
477
useNativeDriver: false
478
}).start(({ finished }) => {
479
if (finished) {
480
Animated.timing(fadeIn, {
481
toValue: 1,
482
duration: 200,
483
useNativeDriver: false
484
}).start();
485
}
486
});
487
};
488
489
return (
490
<Animated.View
491
style={{
492
transform: [{ translateX: slideIn }],
493
opacity: fadeIn
494
}}
495
/>
496
);
497
}
498
```
499
500
### spring()
501
Animates a value according to an analytical spring model based on damped harmonic oscillation.
502
503
```javascript { .api }
504
Animated.spring(
505
value: AnimatedValue | AnimatedValueXY | AnimatedColor,
506
config: {
507
toValue: number | AnimatedValue | { x: number; y: number };
508
restDisplacementThreshold?: number; // default: 0.001
509
restSpeedThreshold?: number; // default: 0.001
510
velocity?: number | { x: number; y: number }; // default: 0
511
bounciness?: number; // default: 8
512
speed?: number; // default: 12
513
tension?: number; // alternative to bounciness/speed
514
friction?: number; // alternative to bounciness/speed
515
stiffness?: number; // alternative spring config
516
damping?: number; // alternative spring config
517
mass?: number; // default: 1
518
useNativeDriver?: boolean; // default: false
519
onComplete?: (result: EndResult) => void;
520
}
521
): CompositeAnimation
522
```
523
524
**Usage:**
525
```javascript
526
// Bouncy spring animation
527
const scale = new Animated.Value(0);
528
529
Animated.spring(scale, {
530
toValue: 1,
531
bounciness: 15,
532
speed: 8,
533
useNativeDriver: false
534
}).start();
535
536
// Physics-based spring
537
Animated.spring(scale, {
538
toValue: 1,
539
tension: 100,
540
friction: 8,
541
velocity: 0.5,
542
useNativeDriver: false
543
}).start();
544
545
// Interactive spring with gesture
546
function SpringButton({ onPress, children }) {
547
const scale = new Animated.Value(1);
548
const opacity = new Animated.Value(1);
549
550
const animateIn = () => {
551
Animated.parallel([
552
Animated.spring(scale, {
553
toValue: 0.95,
554
tension: 300,
555
friction: 10,
556
useNativeDriver: false
557
}),
558
Animated.timing(opacity, {
559
toValue: 0.8,
560
duration: 100,
561
useNativeDriver: false
562
})
563
]).start();
564
};
565
566
const animateOut = () => {
567
Animated.parallel([
568
Animated.spring(scale, {
569
toValue: 1,
570
tension: 300,
571
friction: 10,
572
useNativeDriver: false
573
}),
574
Animated.timing(opacity, {
575
toValue: 1,
576
duration: 100,
577
useNativeDriver: false
578
})
579
]).start();
580
};
581
582
return (
583
<TouchableWithoutFeedback
584
onPressIn={animateIn}
585
onPressOut={animateOut}
586
onPress={onPress}
587
>
588
<Animated.View
589
style={{
590
transform: [{ scale }],
591
opacity
592
}}
593
>
594
{children}
595
</Animated.View>
596
</TouchableWithoutFeedback>
597
);
598
}
599
```
600
601
### decay()
602
Animates a value from an initial velocity to zero based on a decay coefficient.
603
604
```javascript { .api }
605
Animated.decay(
606
value: AnimatedValue | AnimatedValueXY | AnimatedColor,
607
config: {
608
velocity: number | { x: number; y: number };
609
deceleration?: number; // default: 0.998
610
useNativeDriver?: boolean; // default: false
611
onComplete?: (result: EndResult) => void;
612
}
613
): CompositeAnimation
614
```
615
616
**Usage:**
617
```javascript
618
// Scroll momentum simulation
619
function MomentumScroll() {
620
const scrollY = new Animated.Value(0);
621
let lastScrollY = 0;
622
let velocity = 0;
623
624
const handleScroll = (event) => {
625
const currentScrollY = event.nativeEvent.contentOffset.y;
626
velocity = currentScrollY - lastScrollY;
627
lastScrollY = currentScrollY;
628
scrollY.setValue(currentScrollY);
629
};
630
631
const handleScrollEnd = () => {
632
if (Math.abs(velocity) > 0.1) {
633
Animated.decay(scrollY, {
634
velocity: velocity,
635
deceleration: 0.995,
636
useNativeDriver: false
637
}).start();
638
}
639
};
640
641
return (
642
<ScrollView
643
onScroll={handleScroll}
644
onScrollEndDrag={handleScrollEnd}
645
scrollEventThrottle={16}
646
>
647
{/* Content */}
648
</ScrollView>
649
);
650
}
651
```
652
653
## Composition Functions
654
655
### parallel()
656
Starts multiple animations simultaneously with optional coordination.
657
658
```javascript { .api }
659
Animated.parallel(
660
animations: CompositeAnimation[],
661
config?: {
662
stopTogether?: boolean; // default: true
663
}
664
): CompositeAnimation
665
```
666
667
### sequence()
668
Runs animations in sequential order, waiting for each to complete.
669
670
```javascript { .api }
671
Animated.sequence(animations: CompositeAnimation[]): CompositeAnimation
672
```
673
674
### stagger()
675
Starts animations in sequence with successive delays.
676
677
```javascript { .api }
678
Animated.stagger(
679
time: number,
680
animations: CompositeAnimation[]
681
): CompositeAnimation
682
```
683
684
### loop()
685
Continuously repeats an animation with configurable iterations.
686
687
```javascript { .api }
688
Animated.loop(
689
animation: CompositeAnimation,
690
config?: {
691
iterations?: number; // default: -1 (infinite)
692
resetBeforeIteration?: boolean; // default: true
693
}
694
): CompositeAnimation
695
```
696
697
**Usage:**
698
```javascript
699
// Complex choreographed animation
700
function StaggeredCards() {
701
const cards = [0, 1, 2, 3].map(() => ({
702
opacity: new Animated.Value(0),
703
translateY: new Animated.Value(50),
704
scale: new Animated.Value(0.8)
705
}));
706
707
const animateIn = () => {
708
const cardAnimations = cards.map(({ opacity, translateY, scale }) =>
709
Animated.parallel([
710
Animated.timing(opacity, {
711
toValue: 1,
712
duration: 300,
713
useNativeDriver: false
714
}),
715
Animated.spring(translateY, {
716
toValue: 0,
717
tension: 100,
718
friction: 8,
719
useNativeDriver: false
720
}),
721
Animated.spring(scale, {
722
toValue: 1,
723
tension: 120,
724
friction: 7,
725
useNativeDriver: false
726
})
727
])
728
);
729
730
// Stagger the card animations
731
Animated.stagger(100, cardAnimations).start();
732
};
733
734
const pulseAnimation = () => {
735
const pulseScale = new Animated.Value(1);
736
737
return Animated.loop(
738
Animated.sequence([
739
Animated.timing(pulseScale, {
740
toValue: 1.05,
741
duration: 800,
742
useNativeDriver: false
743
}),
744
Animated.timing(pulseScale, {
745
toValue: 1,
746
duration: 800,
747
useNativeDriver: false
748
})
749
]),
750
{ iterations: -1 }
751
);
752
};
753
754
return (
755
<View>
756
{cards.map(({ opacity, translateY, scale }, index) => (
757
<Animated.View
758
key={index}
759
style={{
760
opacity,
761
transform: [{ translateY }, { scale }]
762
}}
763
>
764
<Text>Card {index + 1}</Text>
765
</Animated.View>
766
))}
767
</View>
768
);
769
}
770
```
771
772
## Math Operations
773
774
Combine animated values using mathematical operations for complex derived animations.
775
776
```javascript { .api }
777
Animated.add(a: AnimatedNode | number, b: AnimatedNode | number): AnimatedAddition;
778
Animated.subtract(a: AnimatedNode | number, b: AnimatedNode | number): AnimatedSubtraction;
779
Animated.multiply(a: AnimatedNode | number, b: AnimatedNode | number): AnimatedMultiplication;
780
Animated.divide(a: AnimatedNode | number, b: AnimatedNode | number): AnimatedDivision;
781
Animated.modulo(a: AnimatedNode, modulus: number): AnimatedModulo;
782
Animated.diffClamp(a: AnimatedNode, min: number, max: number): AnimatedDiffClamp;
783
```
784
785
**Usage:**
786
```javascript
787
// Complex derived animations
788
function ParallaxHeader() {
789
const scrollY = new Animated.Value(0);
790
const headerHeight = 200;
791
792
// Clamp scroll for header transformation
793
const headerTranslateY = Animated.diffClamp(
794
scrollY,
795
0,
796
headerHeight
797
).interpolate({
798
inputRange: [0, headerHeight],
799
outputRange: [0, -headerHeight],
800
extrapolate: 'clamp'
801
});
802
803
// Combine multiple values
804
const headerScale = Animated.add(
805
1,
806
Animated.divide(scrollY, headerHeight * 2)
807
);
808
809
const headerOpacity = Animated.subtract(
810
1,
811
Animated.divide(scrollY, headerHeight)
812
);
813
814
return (
815
<View>
816
<Animated.View
817
style={{
818
height: headerHeight,
819
transform: [
820
{ translateY: headerTranslateY },
821
{ scale: headerScale }
822
],
823
opacity: headerOpacity
824
}}
825
>
826
<Text>Parallax Header</Text>
827
</Animated.View>
828
829
<ScrollView
830
onScroll={Animated.event(
831
[{ nativeEvent: { contentOffset: { y: scrollY } } }],
832
{ useNativeDriver: false }
833
)}
834
scrollEventThrottle={16}
835
>
836
{/* Content */}
837
</ScrollView>
838
</View>
839
);
840
}
841
842
// Mathematical operations for physics
843
function PhysicsAnimation() {
844
const x = new Animated.Value(0);
845
const velocity = new Animated.Value(0);
846
847
// Kinetic energy calculation: KE = 0.5 * m * v²
848
const kineticEnergy = Animated.multiply(
849
0.5,
850
Animated.multiply(velocity, velocity)
851
);
852
853
// Oscillation with sine wave
854
const time = new Animated.Value(0);
855
const amplitude = 50;
856
857
const sinePosition = Animated.multiply(
858
amplitude,
859
// Note: In real implementation, you'd need to use interpolation
860
// for trigonometric functions
861
time.interpolate({
862
inputRange: [0, Math.PI * 2],
863
outputRange: [0, 1, 0, -1, 0],
864
extrapolate: 'extend'
865
})
866
);
867
868
return (
869
<Animated.View
870
style={{
871
transform: [{ translateX: sinePosition }]
872
}}
873
/>
874
);
875
}
876
```
877
878
## Event Handling
879
880
### Animated.event()
881
Maps gesture or scroll events directly to animated values for high-performance interactions.
882
883
```javascript { .api }
884
Animated.event(
885
argMapping: Mapping[],
886
config?: {
887
useNativeDriver?: boolean; // default: false
888
listener?: Function;
889
}
890
): Function
891
```
892
893
**Usage:**
894
```javascript
895
// Scroll-driven animations
896
function ScrollParallax() {
897
const scrollY = new Animated.Value(0);
898
899
return (
900
<ScrollView
901
onScroll={Animated.event(
902
[{ nativeEvent: { contentOffset: { y: scrollY } } }],
903
{
904
useNativeDriver: false,
905
listener: (event) => {
906
// Additional scroll handling
907
console.log('Scroll position:', event.nativeEvent.contentOffset.y);
908
}
909
}
910
)}
911
scrollEventThrottle={16}
912
>
913
<Animated.View
914
style={{
915
transform: [{
916
translateY: scrollY.interpolate({
917
inputRange: [0, 100],
918
outputRange: [0, -50],
919
extrapolate: 'clamp'
920
})
921
}]
922
}}
923
>
924
{/* Parallax content */}
925
</Animated.View>
926
</ScrollView>
927
);
928
}
929
930
// Pan gesture handling
931
function PanAnimation() {
932
const pan = new Animated.ValueXY();
933
934
return (
935
<View>
936
<Animated.View
937
{...PanResponder.create({
938
onMoveShouldSetPanResponder: () => true,
939
onPanResponderGrant: () => {
940
pan.setOffset({
941
x: pan.x._value,
942
y: pan.y._value
943
});
944
},
945
onPanResponderMove: Animated.event(
946
[null, { dx: pan.x, dy: pan.y }],
947
{ useNativeDriver: false }
948
),
949
onPanResponderRelease: () => {
950
pan.flattenOffset();
951
Animated.spring(pan, {
952
toValue: { x: 0, y: 0 },
953
useNativeDriver: false
954
}).start();
955
}
956
}).panHandlers}
957
style={{
958
transform: pan.getTranslateTransform()
959
}}
960
>
961
{/* Draggable content */}
962
</Animated.View>
963
</View>
964
);
965
}
966
```
967
968
## Animated Components
969
970
Pre-built animated versions of common React Native components.
971
972
```javascript { .api }
973
const AnimatedComponents: {
974
View: AnimatedComponent<typeof View>;
975
Text: AnimatedComponent<typeof Text>;
976
Image: AnimatedComponent<typeof Image>;
977
ScrollView: AnimatedComponent<typeof ScrollView>;
978
FlatList: AnimatedComponent<typeof FlatList>;
979
SectionList: AnimatedComponent<typeof SectionList>;
980
};
981
```
982
983
### createAnimatedComponent()
984
Creates animated versions of custom components.
985
986
```javascript { .api }
987
Animated.createAnimatedComponent<T>(Component: T): T
988
```
989
990
**Usage:**
991
```javascript
992
// Create custom animated component
993
const AnimatedTouchableOpacity = Animated.createAnimatedComponent(TouchableOpacity);
994
995
function CustomAnimatedButton({ onPress, children }) {
996
const scale = new Animated.Value(1);
997
const opacity = new Animated.Value(1);
998
999
const handlePressIn = () => {
1000
Animated.parallel([
1001
Animated.spring(scale, {
1002
toValue: 0.95,
1003
useNativeDriver: false
1004
}),
1005
Animated.timing(opacity, {
1006
toValue: 0.7,
1007
duration: 100,
1008
useNativeDriver: false
1009
})
1010
]).start();
1011
};
1012
1013
const handlePressOut = () => {
1014
Animated.parallel([
1015
Animated.spring(scale, {
1016
toValue: 1,
1017
useNativeDriver: false
1018
}),
1019
Animated.timing(opacity, {
1020
toValue: 1,
1021
duration: 100,
1022
useNativeDriver: false
1023
})
1024
]).start();
1025
};
1026
1027
return (
1028
<AnimatedTouchableOpacity
1029
onPress={onPress}
1030
onPressIn={handlePressIn}
1031
onPressOut={handlePressOut}
1032
style={{
1033
transform: [{ scale }],
1034
opacity
1035
}}
1036
>
1037
{children}
1038
</AnimatedTouchableOpacity>
1039
);
1040
}
1041
1042
// Advanced custom component with multiple animated properties
1043
const AnimatedGradientView = Animated.createAnimatedComponent(
1044
({ colors, style, children, ...props }) => (
1045
<View
1046
{...props}
1047
style={[
1048
{
1049
background: `linear-gradient(45deg, ${colors.join(', ')})`
1050
},
1051
style
1052
]}
1053
>
1054
{children}
1055
</View>
1056
)
1057
);
1058
```
1059
1060
## Interpolation
1061
1062
Transform animated values into different ranges and types for versatile property mapping.
1063
1064
```javascript { .api }
1065
animatedValue.interpolate({
1066
inputRange: number[];
1067
outputRange: (number | string)[];
1068
easing?: EasingFunction;
1069
extrapolate?: 'extend' | 'identity' | 'clamp';
1070
extrapolateLeft?: 'extend' | 'identity' | 'clamp';
1071
extrapolateRight?: 'extend' | 'identity' | 'clamp';
1072
}): AnimatedInterpolation
1073
```
1074
1075
**Usage:**
1076
```javascript
1077
// Color interpolation
1078
function ColorTransition() {
1079
const animatedValue = new Animated.Value(0);
1080
1081
const backgroundColor = animatedValue.interpolate({
1082
inputRange: [0, 0.5, 1],
1083
outputRange: ['#ff0000', '#ffff00', '#00ff00']
1084
});
1085
1086
const textColor = animatedValue.interpolate({
1087
inputRange: [0, 1],
1088
outputRange: ['rgba(255,255,255,1)', 'rgba(0,0,0,1)']
1089
});
1090
1091
return (
1092
<Animated.View style={{ backgroundColor }}>
1093
<Animated.Text style={{ color: textColor }}>
1094
Color Transition
1095
</Animated.Text>
1096
</Animated.View>
1097
);
1098
}
1099
1100
// Multi-property interpolation
1101
function ComplexInterpolation() {
1102
const scrollY = new Animated.Value(0);
1103
1104
// Multiple interpolated properties from single value
1105
const headerOpacity = scrollY.interpolate({
1106
inputRange: [0, 50, 100],
1107
outputRange: [1, 0.5, 0],
1108
extrapolate: 'clamp'
1109
});
1110
1111
const headerScale = scrollY.interpolate({
1112
inputRange: [0, 100],
1113
outputRange: [1, 0.8],
1114
extrapolate: 'clamp'
1115
});
1116
1117
const titleFontSize = scrollY.interpolate({
1118
inputRange: [0, 100],
1119
outputRange: [24, 18],
1120
extrapolate: 'clamp'
1121
});
1122
1123
const borderRadius = scrollY.interpolate({
1124
inputRange: [0, 50],
1125
outputRange: [0, 15],
1126
extrapolate: 'clamp'
1127
});
1128
1129
return (
1130
<Animated.View
1131
style={{
1132
opacity: headerOpacity,
1133
transform: [{ scale: headerScale }],
1134
borderRadius
1135
}}
1136
>
1137
<Animated.Text
1138
style={{
1139
fontSize: titleFontSize
1140
}}
1141
>
1142
Dynamic Header
1143
</Animated.Text>
1144
</Animated.View>
1145
);
1146
}
1147
```
1148
1149
## Web-Specific Implementation
1150
1151
React Native Web's Animated implementation provides full compatibility with React Native's API while leveraging web-native CSS transitions and transforms for optimal performance.
1152
1153
**Key Features:**
1154
- CSS-based animations for better performance
1155
- Hardware acceleration through CSS transforms
1156
- Full interpolation support including colors and complex values
1157
- Event-driven animations with `Animated.event()`
1158
- Composition and mathematical operations
1159
- Support for custom easing functions
1160
1161
**Performance Notes:**
1162
- Transform animations (translateX, scale, rotate) are hardware accelerated
1163
- Opacity animations perform well across all browsers
1164
- Color interpolations are computed in JavaScript
1165
- Large numbers of simultaneous animations may impact performance
1166
- Consider using `useNativeDriver: true` for transform and opacity animations when available
1167
1168
## Types
1169
1170
```javascript { .api }
1171
interface CompositeAnimation {
1172
start(callback?: EndCallback): void;
1173
stop(): void;
1174
reset(): void;
1175
_startNativeLoop(iterations?: number): void;
1176
_isUsingNativeDriver(): boolean;
1177
}
1178
1179
interface AnimatedValueConfig {
1180
useNativeDriver?: boolean;
1181
}
1182
1183
interface TimingAnimationConfig {
1184
toValue: number | AnimatedValue;
1185
duration?: number;
1186
easing?: EasingFunction;
1187
delay?: number;
1188
useNativeDriver?: boolean;
1189
onComplete?: (result: EndResult) => void;
1190
}
1191
1192
interface SpringAnimationConfig {
1193
toValue: number | AnimatedValue;
1194
restDisplacementThreshold?: number;
1195
restSpeedThreshold?: number;
1196
velocity?: number;
1197
bounciness?: number;
1198
speed?: number;
1199
tension?: number;
1200
friction?: number;
1201
stiffness?: number;
1202
damping?: number;
1203
mass?: number;
1204
useNativeDriver?: boolean;
1205
onComplete?: (result: EndResult) => void;
1206
}
1207
1208
interface DecayAnimationConfig {
1209
velocity: number;
1210
deceleration?: number;
1211
useNativeDriver?: boolean;
1212
onComplete?: (result: EndResult) => void;
1213
}
1214
1215
interface ParallelConfig {
1216
stopTogether?: boolean;
1217
}
1218
1219
interface LoopAnimationConfig {
1220
iterations?: number;
1221
resetBeforeIteration?: boolean;
1222
}
1223
1224
interface InterpolationConfigType {
1225
inputRange: number[];
1226
outputRange: (number | string)[];
1227
easing?: EasingFunction;
1228
extrapolate?: 'extend' | 'identity' | 'clamp';
1229
extrapolateLeft?: 'extend' | 'identity' | 'clamp';
1230
extrapolateRight?: 'extend' | 'identity' | 'clamp';
1231
}
1232
1233
interface EndResult {
1234
finished: boolean;
1235
}
1236
1237
type EndCallback = (result: EndResult) => void;
1238
type ValueListenerCallback = (state: { value: number }) => void;
1239
type ValueXYListenerCallback = (state: { value: { x: number; y: number } }) => void;
1240
1241
type Mapping = { [key: string]: any } | AnimatedValue | null;
1242
1243
interface EventConfig {
1244
useNativeDriver?: boolean;
1245
listener?: Function;
1246
}
1247
```