UNPKG

6.8 kBTypeScriptView Raw
1import { Animated, I18nManager } from 'react-native';
2
3import type {
4 StackHeaderInterpolatedStyle,
5 StackHeaderInterpolationProps,
6} from '../types';
7
8const { add } = Animated;
9
10/**
11 * Standard UIKit style animation for the header where the title fades into the back button label.
12 */
13export function forUIKit({
14 current,
15 next,
16 layouts,
17}: StackHeaderInterpolationProps): StackHeaderInterpolatedStyle {
18 const defaultOffset = 100;
19 const leftSpacing = 27;
20
21 // The title and back button title should cross-fade to each other
22 // When screen is fully open, the title should be in center, and back title should be on left
23 // When screen is closing, the previous title will animate to back title's position
24 // And back title will animate to title's position
25 // We achieve this by calculating the offsets needed to translate title to back title's position and vice-versa
26 const leftLabelOffset = layouts.leftLabel
27 ? (layouts.screen.width - layouts.leftLabel.width) / 2 - leftSpacing
28 : defaultOffset;
29 const titleLeftOffset = layouts.title
30 ? (layouts.screen.width - layouts.title.width) / 2 - leftSpacing
31 : defaultOffset;
32
33 // When the current title is animating to right, it is centered in the right half of screen in middle of transition
34 // The back title also animates in from this position
35 const rightOffset = layouts.screen.width / 4;
36
37 const progress = add(
38 current.progress.interpolate({
39 inputRange: [0, 1],
40 outputRange: [0, 1],
41 extrapolate: 'clamp',
42 }),
43 next
44 ? next.progress.interpolate({
45 inputRange: [0, 1],
46 outputRange: [0, 1],
47 extrapolate: 'clamp',
48 })
49 : 0
50 );
51
52 return {
53 leftButtonStyle: {
54 opacity: progress.interpolate({
55 inputRange: [0.3, 1, 1.5],
56 outputRange: [0, 1, 0],
57 }),
58 },
59 leftLabelStyle: {
60 transform: [
61 {
62 translateX: progress.interpolate({
63 inputRange: [0, 1, 2],
64 outputRange: I18nManager.getConstants().isRTL
65 ? [-rightOffset, 0, leftLabelOffset]
66 : [leftLabelOffset, 0, -rightOffset],
67 }),
68 },
69 ],
70 },
71 rightButtonStyle: {
72 opacity: progress.interpolate({
73 inputRange: [0.3, 1, 1.5],
74 outputRange: [0, 1, 0],
75 }),
76 },
77 titleStyle: {
78 opacity: progress.interpolate({
79 inputRange: [0, 0.4, 1, 1.5],
80 outputRange: [0, 0.1, 1, 0],
81 }),
82 transform: [
83 {
84 translateX: progress.interpolate({
85 inputRange: [0.5, 1, 2],
86 outputRange: I18nManager.getConstants().isRTL
87 ? [-titleLeftOffset, 0, rightOffset]
88 : [rightOffset, 0, -titleLeftOffset],
89 }),
90 },
91 ],
92 },
93 backgroundStyle: {
94 transform: [
95 {
96 translateX: progress.interpolate({
97 inputRange: [0, 1, 2],
98 outputRange: I18nManager.getConstants().isRTL
99 ? [-layouts.screen.width, 0, layouts.screen.width]
100 : [layouts.screen.width, 0, -layouts.screen.width],
101 }),
102 },
103 ],
104 },
105 };
106}
107
108/**
109 * Simple fade animation for the header elements.
110 */
111export function forFade({
112 current,
113 next,
114}: StackHeaderInterpolationProps): StackHeaderInterpolatedStyle {
115 const progress = add(
116 current.progress.interpolate({
117 inputRange: [0, 1],
118 outputRange: [0, 1],
119 extrapolate: 'clamp',
120 }),
121 next
122 ? next.progress.interpolate({
123 inputRange: [0, 1],
124 outputRange: [0, 1],
125 extrapolate: 'clamp',
126 })
127 : 0
128 );
129
130 const opacity = progress.interpolate({
131 inputRange: [0, 1, 2],
132 outputRange: [0, 1, 0],
133 });
134
135 return {
136 leftButtonStyle: { opacity },
137 rightButtonStyle: { opacity },
138 titleStyle: { opacity },
139 backgroundStyle: {
140 opacity: progress.interpolate({
141 inputRange: [0, 1, 1.9, 2],
142 outputRange: [0, 1, 1, 0],
143 }),
144 },
145 };
146}
147
148/**
149 * Simple translate animation to translate the header to left.
150 */
151export function forSlideLeft({
152 current,
153 next,
154 layouts: { screen },
155}: StackHeaderInterpolationProps): StackHeaderInterpolatedStyle {
156 const progress = add(
157 current.progress.interpolate({
158 inputRange: [0, 1],
159 outputRange: [0, 1],
160 extrapolate: 'clamp',
161 }),
162 next
163 ? next.progress.interpolate({
164 inputRange: [0, 1],
165 outputRange: [0, 1],
166 extrapolate: 'clamp',
167 })
168 : 0
169 );
170
171 const translateX = progress.interpolate({
172 inputRange: [0, 1, 2],
173 outputRange: I18nManager.getConstants().isRTL
174 ? [-screen.width, 0, screen.width]
175 : [screen.width, 0, -screen.width],
176 });
177
178 const transform = [{ translateX }];
179
180 return {
181 leftButtonStyle: { transform },
182 rightButtonStyle: { transform },
183 titleStyle: { transform },
184 backgroundStyle: { transform },
185 };
186}
187
188/**
189 * Simple translate animation to translate the header to right.
190 */
191export function forSlideRight({
192 current,
193 next,
194 layouts: { screen },
195}: StackHeaderInterpolationProps): StackHeaderInterpolatedStyle {
196 const progress = add(
197 current.progress.interpolate({
198 inputRange: [0, 1],
199 outputRange: [0, 1],
200 extrapolate: 'clamp',
201 }),
202 next
203 ? next.progress.interpolate({
204 inputRange: [0, 1],
205 outputRange: [0, 1],
206 extrapolate: 'clamp',
207 })
208 : 0
209 );
210
211 const translateX = progress.interpolate({
212 inputRange: [0, 1, 2],
213 outputRange: I18nManager.getConstants().isRTL
214 ? [screen.width, 0, -screen.width]
215 : [-screen.width, 0, screen.width],
216 });
217
218 const transform = [{ translateX }];
219
220 return {
221 leftButtonStyle: { transform },
222 rightButtonStyle: { transform },
223 titleStyle: { transform },
224 backgroundStyle: { transform },
225 };
226}
227
228/**
229 * Simple translate animation to translate the header to slide up.
230 */
231export function forSlideUp({
232 current,
233 next,
234 layouts: { header },
235}: StackHeaderInterpolationProps): StackHeaderInterpolatedStyle {
236 const progress = add(
237 current.progress.interpolate({
238 inputRange: [0, 1],
239 outputRange: [0, 1],
240 extrapolate: 'clamp',
241 }),
242 next
243 ? next.progress.interpolate({
244 inputRange: [0, 1],
245 outputRange: [0, 1],
246 extrapolate: 'clamp',
247 })
248 : 0
249 );
250
251 const translateY = progress.interpolate({
252 inputRange: [0, 1, 2],
253 outputRange: [-header.height, 0, -header.height],
254 });
255
256 const transform = [{ translateY }];
257
258 return {
259 leftButtonStyle: { transform },
260 rightButtonStyle: { transform },
261 titleStyle: { transform },
262 backgroundStyle: { transform },
263 };
264}
265
266export function forNoAnimation(): StackHeaderInterpolatedStyle {
267 return {};
268}