Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,42 @@ Use `{ type: 'none' }` to apply values immediately without animation. Useful for

`onTransitionEnd` fires immediately with `{ finished: true }`.

### Per-Property Transitions

Pass a map instead of a single config to use different transition types per property. This lets you mix timing and spring animations, or use different durations for different properties.

```tsx
<EaseView
animate={{ opacity: visible ? 1 : 0, translateY: visible ? 0 : 30 }}
transition={{
opacity: { type: 'timing', duration: 150, easing: 'easeOut' },
translateY: { type: 'spring', damping: 12, stiffness: 200 },
}}
/>
```

Use `default` as a fallback for properties not explicitly listed:

```tsx
<EaseView
animate={{ opacity: 1, scale: 1.2, translateY: -20 }}
transition={{
default: { type: 'spring', damping: 15, stiffness: 120 },
opacity: { type: 'timing', duration: 200, easing: 'easeOut' },
}}
/>
```

The `scale` key applies to both `scaleX` and `scaleY`. A specific `scaleX` or `scaleY` key takes priority over `scale`.

When no `default` key is provided, library defaults apply by category:
- **Transforms** (translateX/Y, scaleX/Y, rotate, rotateX/Y): spring with damping=15, stiffness=120
- **Other** (opacity, borderRadius, backgroundColor): timing 300ms easeInOut

> **iOS note:** iOS composes all transform sub-properties into a single `CATransform3D` animation. If your map specifies conflicting configs for different transform properties (e.g. spring for `translateX` and timing for `scaleX`), the config from the lowest-index changed property is used.
>
> **Android note:** Android animates `backgroundColor` with `ValueAnimator` (timing only). If a per-property map specifies `type: 'spring'` for `backgroundColor`, it silently falls back to timing 300ms.

### Border Radius

`borderRadius` can be animated just like other properties. It uses hardware-accelerated platform APIs — `ViewOutlineProvider` + `clipToOutline` on Android and `layer.cornerRadius` + `layer.masksToBounds` on iOS. Unlike RN's style-based `borderRadius` (which uses a Canvas drawable on Android), this clips children properly and is GPU-accelerated.
Expand Down Expand Up @@ -400,6 +436,27 @@ Properties not specified in `animate` default to their identity values.

Applies values instantly with no animation. `onTransitionEnd` fires immediately with `{ finished: true }`.

### `TransitionMap`

```tsx
{
default?: SingleTransition; // fallback for unlisted properties
opacity?: SingleTransition;
translateX?: SingleTransition;
translateY?: SingleTransition;
scale?: SingleTransition; // shorthand for scaleX + scaleY
scaleX?: SingleTransition;
scaleY?: SingleTransition;
rotate?: SingleTransition;
rotateX?: SingleTransition;
rotateY?: SingleTransition;
borderRadius?: SingleTransition;
backgroundColor?: SingleTransition;
}
```

`Transition` is `SingleTransition | TransitionMap`. The `transition` prop accepts either form.

## Hardware Layers (Android)

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.
Expand Down
333 changes: 251 additions & 82 deletions android/src/main/java/com/ease/EaseView.kt

Large diffs are not rendered by default.

54 changes: 5 additions & 49 deletions android/src/main/java/com/ease/EaseViewManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.ease
import android.graphics.Color
import com.facebook.react.bridge.Arguments
import com.facebook.react.bridge.ReadableArray
import com.facebook.react.bridge.ReadableMap
import com.facebook.react.bridge.WritableMap
import com.facebook.react.module.annotations.ReactModule
import com.facebook.react.uimanager.PixelUtil
Expand Down Expand Up @@ -126,56 +127,11 @@ class EaseViewManager : ReactViewManager() {
view.initialAnimateBorderRadius = PixelUtil.toPixelFromDIP(value)
}

// --- Transition config setters ---
// --- Transitions config (single ReadableMap) ---

@ReactProp(name = "transitionType")
fun setTransitionType(view: EaseView, value: String?) {
view.transitionType = value ?: "timing"
}

@ReactProp(name = "transitionDuration", defaultInt = 300)
fun setTransitionDuration(view: EaseView, value: Int) {
view.transitionDuration = value
}

@ReactProp(name = "transitionEasingBezier")
fun setTransitionEasingBezier(view: EaseView, value: ReadableArray?) {
if (value != null && value.size() == 4) {
view.transitionEasingBezier = floatArrayOf(
value.getDouble(0).toFloat(),
value.getDouble(1).toFloat(),
value.getDouble(2).toFloat(),
value.getDouble(3).toFloat()
)
} else {
// Fallback: easeInOut
view.transitionEasingBezier = floatArrayOf(0.42f, 0f, 0.58f, 1.0f)
}
}

@ReactProp(name = "transitionDamping", defaultFloat = 15f)
fun setTransitionDamping(view: EaseView, value: Float) {
view.transitionDamping = value
}

@ReactProp(name = "transitionStiffness", defaultFloat = 120f)
fun setTransitionStiffness(view: EaseView, value: Float) {
view.transitionStiffness = value
}

@ReactProp(name = "transitionMass", defaultFloat = 1f)
fun setTransitionMass(view: EaseView, value: Float) {
view.transitionMass = value
}

@ReactProp(name = "transitionLoop")
fun setTransitionLoop(view: EaseView, value: String?) {
view.transitionLoop = value ?: "none"
}

@ReactProp(name = "transitionDelay", defaultInt = 0)
fun setTransitionDelay(view: EaseView, value: Int) {
view.transitionDelay = value.toLong()
@ReactProp(name = "transitions")
fun setTransitions(view: EaseView, value: ReadableMap?) {
view.setTransitionsFromMap(value)
}

// --- Border radius ---
Expand Down
Loading
Loading