Skip to content

Commit aad0b8e

Browse files
docs: update README with loop, onTransitionEnd, and hardware layer docs
1 parent e5dc772 commit aad0b8e

3 files changed

Lines changed: 151 additions & 8 deletions

File tree

README.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ Timing animations transition from one value to another over a fixed duration wit
7171
|---|---|---|---|
7272
| `duration` | `number` | `300` | Duration in milliseconds |
7373
| `easing` | `string` | `'easeInOut'` | Easing curve |
74+
| `loop` | `string` || `'repeat'` restarts from the beginning, `'reverse'` alternates direction |
7475

7576
Available easing curves:
7677

@@ -130,6 +131,28 @@ All properties are set in the `animate` prop as flat values (no transform array)
130131

131132
You can animate any combination of properties simultaneously. All properties share the same transition config.
132133

134+
### Looping Animations
135+
136+
Timing animations can loop infinitely. Use `'repeat'` to restart from the beginning or `'reverse'` to alternate direction.
137+
138+
```tsx
139+
// Pulsing opacity
140+
<EaseView
141+
initialAnimate={{ opacity: 0.3 }}
142+
animate={{ opacity: 1 }}
143+
transition={{ type: 'timing', duration: 1000, easing: 'easeInOut', loop: 'reverse' }}
144+
/>
145+
146+
// Marquee-style scroll
147+
<EaseView
148+
initialAnimate={{ translateX: 0 }}
149+
animate={{ translateX: -300 }}
150+
transition={{ type: 'timing', duration: 3000, easing: 'linear', loop: 'repeat' }}
151+
/>
152+
```
153+
154+
Loop requires `initialAnimate` to define the starting value. Spring animations do not support looping.
155+
133156
### Enter Animations
134157

135158
Use `initialAnimate` to set starting values. On mount, the view starts at `initialAnimate` values and animates to `animate` values.
@@ -187,6 +210,8 @@ A `View` that animates property changes using native platform APIs.
187210
| `animate` | `AnimateProps` | Target values for animated properties |
188211
| `initialAnimate` | `AnimateProps` | Starting values for enter animations (animates to `animate` on mount) |
189212
| `transition` | `Transition` | Animation configuration (timing or spring) |
213+
| `onTransitionEnd` | `(event) => void` | Called when an animation finishes with `{ finished: boolean }` |
214+
| `useHardwareLayer` | `boolean` | Android only — rasterize to GPU texture during animations. See [Hardware Layers](#hardware-layers-android). Default: `false` |
190215
| `style` | `ViewStyle` | Non-animated styles (layout, colors, borders, etc.) |
191216
| `children` | `ReactNode` | Child elements |
192217
| ...rest | `ViewProps` | All other standard View props |
@@ -210,6 +235,7 @@ Properties not specified in `animate` default to their identity values.
210235
type: 'timing';
211236
duration?: number; // default: 300 (ms)
212237
easing?: 'linear' | 'easeIn' | 'easeOut' | 'easeInOut'; // default: 'easeInOut'
238+
loop?: 'repeat' | 'reverse'; // default: none
213239
}
214240
```
215241

@@ -224,6 +250,25 @@ Properties not specified in `animate` default to their identity values.
224250
}
225251
```
226252

253+
## Hardware Layers (Android)
254+
255+
Setting `useHardwareLayer` rasterizes the view into a GPU texture for the duration of the animation. This means animated property changes (opacity, scale, rotation) are composited on the RenderThread without redrawing the view hierarchy — useful for complex views with many children.
256+
257+
```tsx
258+
<EaseView
259+
animate={{ opacity: isVisible ? 1 : 0 }}
260+
useHardwareLayer
261+
/>
262+
```
263+
264+
**Trade-offs:**
265+
266+
- Faster rendering for opacity, scale, and rotation animations (RenderThread compositing).
267+
- Uses additional GPU memory for the off-screen texture (proportional to view size).
268+
- Children that overflow the view's layout bounds are **clipped** by the texture. This causes visual artifacts when animating `translateX`/`translateY` on views with overflowing content.
269+
270+
No-op on iOS where Core Animation already composites off the main thread.
271+
227272
## How It Works
228273

229274
`EaseView` is a native Fabric component. The JS side flattens your `animate` and `transition` props into flat native props. When those props change, the native view:

package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
"ios",
2020
"cpp",
2121
"*.podspec",
22-
"react-native.config.js",
2322
"!ios/build",
2423
"!android/build",
2524
"!android/gradle",
@@ -73,8 +72,11 @@
7372
"@react-native/babel-preset": "0.83.0",
7473
"@react-native/eslint-config": "0.83.0",
7574
"@release-it/conventional-changelog": "^10.0.1",
75+
"@testing-library/jest-native": "^5.4.3",
76+
"@testing-library/react-native": "^13.3.3",
7677
"@types/jest": "^29.5.14",
7778
"@types/react": "^19.2.0",
79+
"@types/react-test-renderer": "^19",
7880
"clang-format": "^1.8.0",
7981
"commitlint": "^19.8.1",
8082
"del-cli": "^6.0.0",
@@ -87,6 +89,7 @@
8789
"react": "19.2.0",
8890
"react-native": "0.83.0",
8991
"react-native-builder-bob": "^0.40.18",
92+
"react-test-renderer": "19.2.0",
9093
"release-it": "^19.0.4",
9194
"turbo": "^2.5.6",
9295
"typescript": "^5.9.2"

yarn.lock

Lines changed: 102 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3453,6 +3453,43 @@ __metadata:
34533453
languageName: node
34543454
linkType: hard
34553455

3456+
"@testing-library/jest-native@npm:^5.4.3":
3457+
version: 5.4.3
3458+
resolution: "@testing-library/jest-native@npm:5.4.3"
3459+
dependencies:
3460+
chalk: "npm:^4.1.2"
3461+
jest-diff: "npm:^29.0.1"
3462+
jest-matcher-utils: "npm:^29.0.1"
3463+
pretty-format: "npm:^29.0.3"
3464+
redent: "npm:^3.0.0"
3465+
peerDependencies:
3466+
react: ">=16.0.0"
3467+
react-native: ">=0.59"
3468+
react-test-renderer: ">=16.0.0"
3469+
checksum: 10c0/9315989dc0377a778f7ec9317b98c1dab9a7e2ebe0ca20a5c75f9dba3a4b486c02452b4399dd1aeef9ebf0007247594c6357f62089f095fde5280ce0344f5e65
3470+
languageName: node
3471+
linkType: hard
3472+
3473+
"@testing-library/react-native@npm:^13.3.3":
3474+
version: 13.3.3
3475+
resolution: "@testing-library/react-native@npm:13.3.3"
3476+
dependencies:
3477+
jest-matcher-utils: "npm:^30.0.5"
3478+
picocolors: "npm:^1.1.1"
3479+
pretty-format: "npm:^30.0.5"
3480+
redent: "npm:^3.0.0"
3481+
peerDependencies:
3482+
jest: ">=29.0.0"
3483+
react: ">=18.2.0"
3484+
react-native: ">=0.71"
3485+
react-test-renderer: ">=18.2.0"
3486+
peerDependenciesMeta:
3487+
jest:
3488+
optional: true
3489+
checksum: 10c0/ba13066536d5b2c0b625220d4320c6ad1e390c3df4f4b614d859ef467c4974ad52aa79269ae98efdba8f5a074644e3d11583a5485312df5a64387976ecf4225a
3490+
languageName: node
3491+
linkType: hard
3492+
34563493
"@tootallnate/quickjs-emscripten@npm:^0.23.0":
34573494
version: 0.23.0
34583495
resolution: "@tootallnate/quickjs-emscripten@npm:0.23.0"
@@ -3600,7 +3637,16 @@ __metadata:
36003637
languageName: node
36013638
linkType: hard
36023639

3603-
"@types/react@npm:^19.2.0":
3640+
"@types/react-test-renderer@npm:^19":
3641+
version: 19.1.0
3642+
resolution: "@types/react-test-renderer@npm:19.1.0"
3643+
dependencies:
3644+
"@types/react": "npm:*"
3645+
checksum: 10c0/799654e430df10aeaf267d71507fb64ec151359ead7e3774111bfd4abce7e0911dba461811195c06c22a6d17496ea92537d3185320ff4112fe29954cad1b9152
3646+
languageName: node
3647+
linkType: hard
3648+
3649+
"@types/react@npm:*, @types/react@npm:^19.2.0":
36043650
version: 19.2.14
36053651
resolution: "@types/react@npm:19.2.14"
36063652
dependencies:
@@ -8130,7 +8176,7 @@ __metadata:
81308176
languageName: node
81318177
linkType: hard
81328178

8133-
"jest-diff@npm:^29.7.0":
8179+
"jest-diff@npm:^29.0.1, jest-diff@npm:^29.7.0":
81348180
version: 29.7.0
81358181
resolution: "jest-diff@npm:29.7.0"
81368182
dependencies:
@@ -8255,7 +8301,7 @@ __metadata:
82558301
languageName: node
82568302
linkType: hard
82578303

8258-
"jest-matcher-utils@npm:30.3.0":
8304+
"jest-matcher-utils@npm:30.3.0, jest-matcher-utils@npm:^30.0.5":
82598305
version: 30.3.0
82608306
resolution: "jest-matcher-utils@npm:30.3.0"
82618307
dependencies:
@@ -8267,7 +8313,7 @@ __metadata:
82678313
languageName: node
82688314
linkType: hard
82698315

8270-
"jest-matcher-utils@npm:^29.7.0":
8316+
"jest-matcher-utils@npm:^29.0.1, jest-matcher-utils@npm:^29.7.0":
82718317
version: 29.7.0
82728318
resolution: "jest-matcher-utils@npm:29.7.0"
82738319
dependencies:
@@ -9551,6 +9597,13 @@ __metadata:
95519597
languageName: node
95529598
linkType: hard
95539599

9600+
"min-indent@npm:^1.0.0":
9601+
version: 1.0.1
9602+
resolution: "min-indent@npm:1.0.1"
9603+
checksum: 10c0/7e207bd5c20401b292de291f02913230cb1163abca162044f7db1d951fa245b174dc00869d40dd9a9f32a885ad6a5f3e767ee104cf278f399cb4e92d3f582d5c
9604+
languageName: node
9605+
linkType: hard
9606+
95549607
"minimatch@npm:^10.2.2":
95559608
version: 10.2.4
95569609
resolution: "minimatch@npm:10.2.4"
@@ -10467,7 +10520,7 @@ __metadata:
1046710520
languageName: node
1046810521
linkType: hard
1046910522

10470-
"pretty-format@npm:30.3.0":
10523+
"pretty-format@npm:30.3.0, pretty-format@npm:^30.0.5":
1047110524
version: 30.3.0
1047210525
resolution: "pretty-format@npm:30.3.0"
1047310526
dependencies:
@@ -10478,7 +10531,7 @@ __metadata:
1047810531
languageName: node
1047910532
linkType: hard
1048010533

10481-
"pretty-format@npm:^29.0.0, pretty-format@npm:^29.7.0":
10534+
"pretty-format@npm:^29.0.0, pretty-format@npm:^29.0.3, pretty-format@npm:^29.7.0":
1048210535
version: 29.7.0
1048310536
resolution: "pretty-format@npm:29.7.0"
1048410537
dependencies:
@@ -10658,6 +10711,13 @@ __metadata:
1065810711
languageName: node
1065910712
linkType: hard
1066010713

10714+
"react-is@npm:^19.2.0":
10715+
version: 19.2.4
10716+
resolution: "react-is@npm:19.2.4"
10717+
checksum: 10c0/477a7cfc900f24194606e315fa353856a3a13487ea8eca841678817cad4daef64339ea0d1e84e58459fc75dbe0d9ba00bb0cc626db3d07e0cf31edc64cb4fa37
10718+
languageName: node
10719+
linkType: hard
10720+
1066110721
"react-native-builder-bob@npm:^0.40.18":
1066210722
version: 0.40.18
1066310723
resolution: "react-native-builder-bob@npm:0.40.18"
@@ -10725,8 +10785,11 @@ __metadata:
1072510785
"@react-native/babel-preset": "npm:0.83.0"
1072610786
"@react-native/eslint-config": "npm:0.83.0"
1072710787
"@release-it/conventional-changelog": "npm:^10.0.1"
10788+
"@testing-library/jest-native": "npm:^5.4.3"
10789+
"@testing-library/react-native": "npm:^13.3.3"
1072810790
"@types/jest": "npm:^29.5.14"
1072910791
"@types/react": "npm:^19.2.0"
10792+
"@types/react-test-renderer": "npm:^19"
1073010793
clang-format: "npm:^1.8.0"
1073110794
commitlint: "npm:^19.8.1"
1073210795
del-cli: "npm:^6.0.0"
@@ -10739,6 +10802,7 @@ __metadata:
1073910802
react: "npm:19.2.0"
1074010803
react-native: "npm:0.83.0"
1074110804
react-native-builder-bob: "npm:^0.40.18"
10805+
react-test-renderer: "npm:19.2.0"
1074210806
release-it: "npm:^19.0.4"
1074310807
turbo: "npm:^2.5.6"
1074410808
typescript: "npm:^5.9.2"
@@ -10873,6 +10937,18 @@ __metadata:
1087310937
languageName: node
1087410938
linkType: hard
1087510939

10940+
"react-test-renderer@npm:19.2.0":
10941+
version: 19.2.0
10942+
resolution: "react-test-renderer@npm:19.2.0"
10943+
dependencies:
10944+
react-is: "npm:^19.2.0"
10945+
scheduler: "npm:^0.27.0"
10946+
peerDependencies:
10947+
react: ^19.2.0
10948+
checksum: 10c0/cc116b908489316f06881bf7392c5fad4b5f66be42d2f04788f4179a19e86674d54f1006b33fe9eba28bde6edb4cb38764ab75b416f28d02e0182c5552c97551
10949+
languageName: node
10950+
linkType: hard
10951+
1087610952
"react@npm:19.2.0":
1087710953
version: 19.2.0
1087810954
resolution: "react@npm:19.2.0"
@@ -10898,6 +10974,16 @@ __metadata:
1089810974
languageName: node
1089910975
linkType: hard
1090010976

10977+
"redent@npm:^3.0.0":
10978+
version: 3.0.0
10979+
resolution: "redent@npm:3.0.0"
10980+
dependencies:
10981+
indent-string: "npm:^4.0.0"
10982+
strip-indent: "npm:^3.0.0"
10983+
checksum: 10c0/d64a6b5c0b50eb3ddce3ab770f866658a2b9998c678f797919ceb1b586bab9259b311407280bd80b804e2a7c7539b19238ae6a2a20c843f1a7fcff21d48c2eae
10984+
languageName: node
10985+
linkType: hard
10986+
1090110987
"reflect.getprototypeof@npm:^1.0.6, reflect.getprototypeof@npm:^1.0.9":
1090210988
version: 1.0.10
1090310989
resolution: "reflect.getprototypeof@npm:1.0.10"
@@ -11243,7 +11329,7 @@ __metadata:
1124311329
languageName: node
1124411330
linkType: hard
1124511331

11246-
"scheduler@npm:0.27.0":
11332+
"scheduler@npm:0.27.0, scheduler@npm:^0.27.0":
1124711333
version: 0.27.0
1124811334
resolution: "scheduler@npm:0.27.0"
1124911335
checksum: 10c0/4f03048cb05a3c8fddc45813052251eca00688f413a3cee236d984a161da28db28ba71bd11e7a3dd02f7af84ab28d39fb311431d3b3772fed557945beb00c452
@@ -11835,6 +11921,15 @@ __metadata:
1183511921
languageName: node
1183611922
linkType: hard
1183711923

11924+
"strip-indent@npm:^3.0.0":
11925+
version: 3.0.0
11926+
resolution: "strip-indent@npm:3.0.0"
11927+
dependencies:
11928+
min-indent: "npm:^1.0.0"
11929+
checksum: 10c0/ae0deaf41c8d1001c5d4fbe16cb553865c1863da4fae036683b474fa926af9fc121e155cb3fc57a68262b2ae7d5b8420aa752c97a6428c315d00efe2a3875679
11930+
languageName: node
11931+
linkType: hard
11932+
1183811933
"strip-json-comments@npm:^3.1.1":
1183911934
version: 3.1.1
1184011935
resolution: "strip-json-comments@npm:3.1.1"

0 commit comments

Comments
 (0)