diff --git a/README.md b/README.md
index 5d7d623..e8cfe7f 100644
--- a/README.md
+++ b/README.md
@@ -46,7 +46,8 @@ or in Alloy:
Name | Parameter | Info | Platforms
--- | --- | --- | -- |
start() | | Starts an animation from the beginning | iOS, Android |
-start(int from, int to) | Startframe, Endframe | Plays an animation from frame `from` to `to` | iOS, Android |
+start(int from, int to) | Startframe, Endframe | Plays an animation from frame `from` to `to` | Android |
+start({string animationName, bool loop}) | | Plays the rive animation | Android |
pause() | | Pause an animation | iOS, Android |
resume() | | Resumes an animation from the current point | iOS, Android |
stop() | | Stops an animation an resets it | iOS, Android |
@@ -56,14 +57,16 @@ setText(String layer, String text) | Layer, Text | Sets the text in the layer `l
## Properties
-Name | Parameter | Info | Platforms
---- | --- | --- | --- |
-progress | float | Get/set the current progress (in percentage) | iOS, Android |
-loop | boolean | Get/set if the animation should loop | iOS, Android |
-speed | float | Get/set the speed of the animation | iOS, Android |
-duration | float | Get/set the duration of the animation | iOS, Android |
-isPlaying | boolean | Get the animation status | iOS, Android |
-newRenderingEngineEnabled | boolean | Use the core animation background rendering engine instead of the main thread | iOS |
+Name | Parameter | Info | Framework | Platforms
+--- | --- | --- | --- | --- |
+progress | float | Get/set the current progress (in percentage) | Lottie | Android |
+loop | boolean | Get/set if the animation should loop | Lottie | Android |
+speed | float | Get/set the speed of the animation | Lottie | Android |
+duration | float | Get/set the duration of the animation | Lottie | Android |
+isPlaying | boolean | Get the animation status | Lottie | Android |
+cache() | boolean | - | Lottie | iOS |
+animationName | String or Array | Sets the Rive animation name | Rive | Android |
+newRenderingEngineEnabled | boolean | Use the core animation background rendering engine instead of the main thread | Lottie | iOS |
creation (tss) only:
@@ -74,6 +77,7 @@ file | String | JSON file. Files go into app/assets/ (Alloy)
Android: Suppor
jsonString | String | Pass a raw JSON string to the module | iOS |
loop | boolean | loop the animation | iOS, Android |
autoStart | boolean | automatically start the animation | iOS, Android |
+animationType | int | One of the constants `ANIMATION_LOTTIE` or `ANIMATION_RIVE` | iOS, Android |
## Events
@@ -83,6 +87,24 @@ Name | Info | Properties | Platforms
complete | When the animation is done | Status:int, Loop:boolean | iOS, Android |
update | Fires during the animation | Frame:int, status:int (ANIMATION_START, ANIMATION_END, ANIMATION_CANCEL, ANIMATION_REPEAT, ANIMATION_RUNNING) | Android |
+## Constants
+
+Name | Platforms
+--- | --- |
+ANIMATION_RIVE | Android |
+ANIMATION_LOTTIE | Android |
+
+used in setValueDelegateForKeyPath.type (iOS):
+
+Name | Platforms
+--- | --- |
+CALLBACK_COLOR_VALUE | iOS |
+CALLBACK_NUMBER_VALUE | iOS |
+CALLBACK_POINT_VALUE | iOS |
+CALLBACK_SIZE_VALUE | iOS |
+CALLBACK_PATH_VALUE | iOS |
+
+
## Example
```xml
diff --git a/android/build.gradle b/android/build.gradle
index f923d76..7a51fc9 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -3,5 +3,7 @@ repositories {
}
dependencies {
+ implementation "androidx.startup:startup-runtime:1.1.0"
implementation 'com.airbnb.android:lottie:5.2.0'
+ implementation 'app.rive:rive-android:4.2.2'
}
diff --git a/android/manifest b/android/manifest
index 21657cd..cb9fdaa 100644
--- a/android/manifest
+++ b/android/manifest
@@ -2,7 +2,7 @@
# this is your module manifest and used by Titanium
# during compilation, packaging, distribution, etc.
#
-version: 4.3.0
+version: 4.4.0
apiversion: 4
architectures: arm64-v8a armeabi-v7a x86 x86_64
description: ti.animation
diff --git a/android/platform/android/res/layout/layout_rive.xml b/android/platform/android/res/layout/layout_rive.xml
new file mode 100644
index 0000000..e424fba
--- /dev/null
+++ b/android/platform/android/res/layout/layout_rive.xml
@@ -0,0 +1,12 @@
+
+
+
diff --git a/android/src/ti/animation/AnimationView.java b/android/src/ti/animation/AnimationView.java
index 53a4f74..26dfcba 100644
--- a/android/src/ti/animation/AnimationView.java
+++ b/android/src/ti/animation/AnimationView.java
@@ -7,10 +7,18 @@
*/
package ti.animation;
+import static ti.animation.TiAnimationModule.ANIMATION_LOTTIE;
+import static ti.animation.TiAnimationModule.ANIMATION_RIVE;
+
+import androidx.annotation.NonNull;
+import androidx.startup.AppInitializer;
+
import android.animation.Animator;
import android.animation.ValueAnimator;
+import android.annotation.SuppressLint;
import android.content.res.Resources;
import android.view.LayoutInflater;
+import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView.ScaleType;
@@ -34,20 +42,39 @@
import org.appcelerator.titanium.view.TiUIView;
import org.json.JSONObject;
+import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+
+import app.rive.runtime.kotlin.RiveAnimationView;
+import app.rive.runtime.kotlin.RiveArtboardRenderer;
+import app.rive.runtime.kotlin.RiveInitializer;
+import app.rive.runtime.kotlin.core.Alignment;
+import app.rive.runtime.kotlin.core.Direction;
+import app.rive.runtime.kotlin.core.Fit;
+import app.rive.runtime.kotlin.core.LinearAnimationInstance;
+import app.rive.runtime.kotlin.core.Loop;
+import app.rive.runtime.kotlin.core.PlayableInstance;
+import app.rive.runtime.kotlin.core.StateMachineInstance;
public class AnimationView extends TiUIView implements LottieOnCompositionLoadedListener {
private static final String LCAT = "AnimationViewProxy";
-
- private final LottieAnimationView lottieView;
private final TiViewProxy proxy;
- private final TextDelegate delegate;
+ public int animationType = ANIMATION_LOTTIE;
+ ByteArrayOutputStream byteBuffer;
+ private LottieAnimationView lottieView;
+ private RiveAnimationView riveView;
+ private TextDelegate delegate;
private KrollFunction callbackReady = null;
private float initialDuration = 0;
private ValueAnimator va = null;
+ @SuppressLint("ClickableViewAccessibility")
AnimationView(TiViewProxy proxy) {
super(proxy);
@@ -57,29 +84,46 @@ public class AnimationView extends TiUIView implements LottieOnCompositionLoaded
View viewWrapper;
int resId_viewHolder;
- int resId_lottie;
+ int resId_aniView;
- resId_viewHolder = resources.getIdentifier("layout_lottie", "layout", packageName);
- resId_lottie = resources.getIdentifier("animation_view", "id", packageName);
+ if (TiConvert.toInt(proxy.getProperty("animationType")) == ANIMATION_RIVE) {
+ AppInitializer.getInstance(TiApplication.getAppCurrentActivity())
+ .initializeComponent(RiveInitializer.class);
+ resId_viewHolder = resources.getIdentifier("layout_rive", "layout", packageName);
+ } else {
+ resId_viewHolder = resources.getIdentifier("layout_lottie", "layout", packageName);
+ }
+ resId_aniView = resources.getIdentifier("animation_view", "id", packageName);
LayoutInflater inflater = LayoutInflater.from(proxy.getActivity());
viewWrapper = inflater.inflate(resId_viewHolder, null);
- lottieView = viewWrapper.findViewById(resId_lottie);
- delegate = new TextDelegate(lottieView);
- setNativeView(viewWrapper);
-
- setScaleMode(TiConvert.toString(proxy.getProperty("scaleMode")));
- lottieView.addAnimatorUpdateListener(new AnimatorUpdateListener());
- lottieView.addAnimatorListener(new AnimatorListener());
- lottieView.addLottieOnCompositionLoadedListener(this);
-
- if (TiConvert.toBoolean(proxy.getProperty("disableHardwareAcceleration"))) {
- lottieView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
+ if (TiConvert.toInt(proxy.getProperty("animationType")) == ANIMATION_RIVE) {
+ riveView = viewWrapper.findViewById(resId_aniView);
+ animationType = ANIMATION_RIVE;
+ MotionEvent mEvent = null;
+ riveView.setOnTouchListener((view, motionEvent) -> {
+ if (motionEvent.getAction() == MotionEvent.ACTION_UP) {
+ fireEvent("click", new KrollDict());
+ }
+ return false;
+ });
} else {
- lottieView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+ lottieView = viewWrapper.findViewById(resId_aniView);
+ delegate = new TextDelegate(lottieView);
+ setScaleMode(TiConvert.toString(proxy.getProperty("scaleMode")));
+ lottieView.addAnimatorUpdateListener(new AnimatorUpdateListener());
+ lottieView.addAnimatorListener(new AnimatorListener());
+ lottieView.addLottieOnCompositionLoadedListener(this);
+
+ if (TiConvert.toBoolean(proxy.getProperty("disableHardwareAcceleration"))) {
+ lottieView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
+ } else {
+ lottieView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+ }
+ lottieView.enableMergePathsForKitKatAndAbove(TiConvert.toBoolean(proxy.getProperty("mergePath")));
}
- lottieView.enableMergePathsForKitKatAndAbove(TiConvert.toBoolean(proxy.getProperty("mergePath")));
+ setNativeView(viewWrapper);
}
@Override
@@ -91,19 +135,23 @@ public void processProperties(KrollDict d) {
}
if (d.containsKey("disableHardwareAcceleration")) {
if (d.getBoolean("disableHardwareAcceleration")) {
- lottieView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
+ if (lottieView != null) lottieView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
} else {
- lottieView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+ if (lottieView != null) lottieView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
}
}
if (d.containsKey("loop")) {
- lottieView.setRepeatCount(d.getBoolean("loop") ? LottieDrawable.INFINITE : 0);
+ if (animationType == ANIMATION_LOTTIE) {
+ if (lottieView != null)
+ lottieView.setRepeatCount(d.getBoolean("loop") ? LottieDrawable.INFINITE : 0);
+ }
}
if (d.containsKey("ready")) {
callbackReady = (KrollFunction) d.get("ready");
}
if (d.containsKey("mergePath")) {
- lottieView.enableMergePathsForKitKatAndAbove(d.getBoolean("mergePath"));
+ if (lottieView != null)
+ lottieView.enableMergePathsForKitKatAndAbove(d.getBoolean("mergePath"));
}
if (d.containsKey("progress")) {
setProgress(Float.parseFloat(d.getString("progress")));
@@ -146,16 +194,20 @@ public void propertyChanged(String key, Object oldValue, Object newValue, KrollP
private void setScaleMode(String smode) {
// Set scale mode on view
//
+ if (animationType == ANIMATION_RIVE) {
+ return;
+ }
+
switch (smode) {
case "center":
- lottieView.setScaleType(ScaleType.CENTER);
+ if (lottieView != null) lottieView.setScaleType(ScaleType.CENTER);
break;
case "centerCrop":
- lottieView.setScaleType(ScaleType.CENTER_CROP);
+ if (lottieView != null) lottieView.setScaleType(ScaleType.CENTER_CROP);
break;
case "centerInside":
default:
- lottieView.setScaleType(ScaleType.CENTER_INSIDE);
+ if (lottieView != null) lottieView.setScaleType(ScaleType.CENTER_INSIDE);
break;
}
}
@@ -211,21 +263,76 @@ void loadFile(String f) {
if (file.exists()) {
try {
InputStream stream = file.getInputStream();
- int size = stream.available();
- byte[] buffer = new byte[size];
- stream.read(buffer);
- String json = new String(buffer, StandardCharsets.UTF_8);
- parseJson(json);
- lottieView.setAnimation(url.replaceAll("file:///android_asset/", ""));
+
+ if (animationType == ANIMATION_RIVE) {
+ byteBuffer = new ByteArrayOutputStream();
+ int bufferSize = 1024;
+ byte[] buffer = new byte[bufferSize];
+ int len = 0;
+ while ((len = stream.read(buffer)) != -1) {
+ byteBuffer.write(buffer, 0, len);
+ }
+
+ String artboard = null;
+ String ani = null;
+ String state = null;
+ Loop loop = Loop.ONESHOT;
+
+ if (proxy.hasPropertyAndNotNull("artboardName")) {
+ artboard = TiConvert.toString(proxy.getProperty("artboardName"));
+ }
+ if (proxy.hasPropertyAndNotNull("animationName")) {
+ ani = TiConvert.toString(proxy.getProperty("animationName"));
+ }
+ if (proxy.hasPropertyAndNotNull("stateName")) {
+ state = TiConvert.toString(proxy.getProperty("stateName"));
+ }
+ if (proxy.hasPropertyAndNotNull("loop")) {
+ if (TiConvert.toInt(proxy.getProperty("loop")) == 0) {
+ loop = Loop.ONESHOT;
+ } else if (TiConvert.toInt(proxy.getProperty("loop")) == 1) {
+ loop = Loop.LOOP;
+ }
+ }
+ riveView.setRiveBytes(byteBuffer.toByteArray(),
+ artboard,
+ ani,
+ state,
+ true,
+ Fit.CONTAIN,
+ Alignment.CENTER,
+ loop);
+ } else {
+ int size = stream.available();
+ byte[] buffer = new byte[size];
+ stream.read(buffer);
+ String json = new String(buffer, StandardCharsets.UTF_8);
+ parseJson(json);
+ lottieView.setAnimation(url.replaceAll("file:///android_asset/", ""));
+ }
} catch (Exception e) {
- Log.e(LCAT, "Error opening file " + file.name());
+ Log.e(LCAT, "Error opening file " + file.name() + "\n" + e.getMessage());
}
} else {
Log.e(LCAT, "File " + file.name() + " not found!");
}
}
+ void startAnimation(Object data) {
+ if (animationType == ANIMATION_RIVE) {
+ HashMap kd = (HashMap) data;
+ String aniName = TiConvert.toString(kd.get("animationName"));
+ Boolean loop = TiConvert.toBoolean(kd.get("loop"));
+ Loop l = Loop.ONESHOT;
+ if (loop) {
+ l = Loop.LOOP;
+ }
+ riveView.play(aniName, l, Direction.AUTO, false, false);
+ }
+ }
+
void startAnimation(int startFrame, int endFrame) {
+ if (animationType == ANIMATION_RIVE) return;
lottieView.cancelAnimation();
lottieView.setProgress(0f);
proxy.setProperty("paused", false);
@@ -294,28 +401,41 @@ public void onAnimationEnd(Animator animation) {
void pauseAnimation() {
proxy.setProperty("paused", true);
- if (va != null) {
- va.pause();
+ if (animationType == ANIMATION_RIVE) {
+ riveView.pause();
} else {
- lottieView.pauseAnimation();
+ if (va != null) {
+ va.pause();
+ } else {
+ lottieView.pauseAnimation();
+ }
}
}
void resumeAnimation() {
proxy.setProperty("paused", false);
- if (va != null) {
- va.resume();
+ if (animationType == ANIMATION_RIVE) {
+ riveView.play(Loop.AUTO, Direction.AUTO, true);
} else {
- lottieView.resumeAnimation();
+ if (va != null) {
+ va.resume();
+ } else {
+ lottieView.resumeAnimation();
+ }
}
}
void stopAnimation() {
proxy.setProperty("paused", false);
- if (va != null) {
- va.cancel();
+
+ if (animationType == ANIMATION_RIVE) {
+ riveView.stop();
} else {
- lottieView.cancelAnimation();
+ if (va != null) {
+ va.cancel();
+ } else {
+ lottieView.cancelAnimation();
+ }
}
}
@@ -324,21 +444,53 @@ void setText(String layer, String text) {
}
float getProgress() {
+ if (animationType == ANIMATION_RIVE) return 0;
return lottieView.getProgress();
}
void setProgress(float val) {
+ if (animationType == ANIMATION_RIVE) return;
lottieView.setProgress(val);
}
int getFrame() {
+ if (animationType == ANIMATION_RIVE) return 0;
return lottieView.getFrame();
}
void setFrame(int val) {
+ if (animationType == ANIMATION_RIVE) return;
lottieView.setFrame(val);
}
+ public void setAnimationName(Object animationName) {
+ if (animationType == ANIMATION_RIVE) {
+ if (animationName instanceof String) {
+ riveView.play((String) animationName, Loop.ONESHOT, Direction.AUTO, false, true);
+ } else if (animationName instanceof Object[]) {
+ Object[] objVal = (Object[]) animationName;
+ List lst = new ArrayList();
+ for (Object s : objVal) {
+ lst.add((String) s);
+ }
+ riveView.play(lst, Loop.ONESHOT, Direction.AUTO, false, true);
+ }
+ }
+ }
+
+ public void resetAnimation() {
+ if (animationType == ANIMATION_RIVE) {
+ try {
+ riveView.stop();
+ riveView.clearAnimation();
+ riveView.reset();
+ riveView.stop();
+ } catch (Exception e) {
+ Log.e(LCAT, e.getMessage());
+ }
+ }
+ }
+
protected class AnimatorUpdateListener implements ValueAnimator.AnimatorUpdateListener {
public void onAnimationUpdate(ValueAnimator animation) {
KrollDict event = new KrollDict();
@@ -375,4 +527,5 @@ public void onAnimationRepeat(Animator animation) {
((AnimationViewProxy) proxy).completeEvent(event);
}
}
+
}
diff --git a/android/src/ti/animation/AnimationViewProxy.java b/android/src/ti/animation/AnimationViewProxy.java
index b4affd2..bca3d4c 100644
--- a/android/src/ti/animation/AnimationViewProxy.java
+++ b/android/src/ti/animation/AnimationViewProxy.java
@@ -7,6 +7,8 @@
*/
package ti.animation;
+import static ti.animation.TiAnimationModule.ANIMATION_LOTTIE;
+
import android.app.Activity;
import android.os.Message;
@@ -23,7 +25,7 @@
@Kroll.proxy(creatableInModule = TiAnimationModule.class,
propertyAccessors = {"file", "scaleMode", "disableHardwareAcceleration", "mergePath", "update",
"autoStart", "loop", "assetFolder", "width", "height", "duration", "paused", "speed",
- "startFrame", "endFrame", "json"})
+ "startFrame", "endFrame", "json", "animationType", "artboardName", "stateName"})
public class AnimationViewProxy extends TiViewProxy {
static final int MSG_START_ANIMATION = KrollProxy.MSG_LAST_ID + 101;
@@ -31,6 +33,7 @@ public class AnimationViewProxy extends TiViewProxy {
static final int MSG_PAUSE_ANIMATION = KrollProxy.MSG_LAST_ID + 103;
static final int MSG_RESUME_ANIMATION = KrollProxy.MSG_LAST_ID + 104;
static final int MSG_STOP_ANIMATION = KrollProxy.MSG_LAST_ID + 105;
+ static final int MSG_RESET_ANIMATION = KrollProxy.MSG_LAST_ID + 106;
@Kroll.constant
static final int ANIMATION_START = 1;
@Kroll.constant
@@ -57,6 +60,7 @@ public AnimationViewProxy() {
defaultValues.put("duration", 0);
defaultValues.put("file", "");
defaultValues.put("json", "");
+ defaultValues.put("animationType", ANIMATION_LOTTIE);
defaultValues.put("paused", false);
}
@@ -83,8 +87,12 @@ public boolean handleMessage(Message message) {
}
case MSG_START_ANIMATION: {
result = (AsyncResult) message.obj;
- int[] frames = (int[]) result.getArg();
- getView().startAnimation(frames[0], frames[1]);
+ if (result.getArg() instanceof Object) {
+ getView().startAnimation(result.getArg());
+ } else {
+ int[] frames = (int[]) result.getArg();
+ getView().startAnimation(frames[0], frames[1]);
+ }
result.setResult(null);
return true;
}
@@ -103,6 +111,11 @@ public boolean handleMessage(Message message) {
result.setResult(null);
return true;
}
+ case MSG_RESET_ANIMATION: {
+ getView().resetAnimation();
+ result.setResult(null);
+ return true;
+ }
}
return super.handleMessage(message);
@@ -118,6 +131,19 @@ public void start(@Kroll.argument(optional = true) int fromFrame, @Kroll.argumen
}
}
+ @Kroll.method
+ public void start(@Kroll.argument(optional = true) Object data) {
+ if (data != null) {
+ if (TiApplication.isUIThread()) {
+ getView().startAnimation(data);
+ } else {
+ TiMessenger.sendBlockingMainMessage(getMainHandler().obtainMessage(MSG_START_ANIMATION), data);
+ }
+ } else {
+ start(-1, -1);
+ }
+ }
+
@Kroll.method
public void resume() {
if (TiApplication.isUIThread()) {
@@ -127,6 +153,16 @@ public void resume() {
}
}
+ @Kroll.getProperty
+ public String getAnimationName() {
+ return "";
+ }
+
+ @Kroll.setProperty
+ public void setAnimationName(Object animationName) {
+ getView().setAnimationName(animationName);
+ }
+
@Kroll.method
public void stop() {
if (TiApplication.isUIThread()) {
@@ -145,6 +181,15 @@ public void pause() {
}
}
+ @Kroll.method
+ public void reset() {
+ if (TiApplication.isUIThread()) {
+ getView().resetAnimation();
+ } else {
+ TiMessenger.sendBlockingMainMessage(getMainHandler().obtainMessage(MSG_RESET_ANIMATION));
+ }
+ }
+
// clang-format off
@Kroll.setProperty
@Kroll.method
@@ -156,7 +201,6 @@ public void setText(String layer, String text)
// clang-format off
@Kroll.getProperty
- @Kroll.method
public float getProgress()
// clang-format on
{
@@ -165,7 +209,6 @@ public float getProgress()
// clang-format off
@Kroll.setProperty
- @Kroll.method
public void setProgress(float val)
// clang-format on
{
@@ -174,7 +217,6 @@ public void setProgress(float val)
// clang-format off
@Kroll.getProperty
- @Kroll.method
public int getFrame()
// clang-format on
{
@@ -183,7 +225,6 @@ public int getFrame()
// clang-format off
@Kroll.setProperty
- @Kroll.method
public void setFrame(int val)
// clang-format on
{
diff --git a/android/src/ti/animation/TiAnimationModule.java b/android/src/ti/animation/TiAnimationModule.java
index 6c1187b..8d73ce0 100644
--- a/android/src/ti/animation/TiAnimationModule.java
+++ b/android/src/ti/animation/TiAnimationModule.java
@@ -8,9 +8,13 @@
package ti.animation;
import org.appcelerator.kroll.KrollModule;
+import org.appcelerator.kroll.annotations.Kroll;
import org.appcelerator.kroll.annotations.Kroll.module;
@module(name = "TiAnimation", id = "ti.animation")
public class TiAnimationModule extends KrollModule {
-
+ @Kroll.constant
+ static final int ANIMATION_LOTTIE = 0;
+ @Kroll.constant
+ static final int ANIMATION_RIVE = 1;
}
diff --git a/example/app.js b/example/app.js
index e320cf8..54ac2a4 100644
--- a/example/app.js
+++ b/example/app.js
@@ -1,89 +1,156 @@
const TiAnimation = require('ti.animation');
+const isAndroid = (Ti.Platform.osname == 'android');
+var offset = 0;
+var isDouble = false;
+var isLoop = false;
+var isDay = true;
+
+if (OS_IOS){
+ TiAnimation.newRenderingEngineEnabled = true;
+}
-const isAndroid = (Ti.Platform.osname === 'android');
-let offset = 20;
-let isDouble = false;
+const win = Ti.UI.createWindow({
+ backgroundColor: '#fff',
+ title: 'Titanium demo',
+ fullscreen: true
+});
-TiAnimation.newRenderingEngineEnabled = true; // iOS-only: Use the CoreAnimation background rendering engine instead of the main thread
+var buttonRow = Ti.UI.createView({
+ height: Ti.UI.SIZE,
+ width: Ti.UI.SIZE,
+ layout: "horizontal",
+ top: 10
+});
+var buttonRow2 = Ti.UI.createView({
+ height: Ti.UI.SIZE,
+ width: Ti.UI.SIZE,
+ layout: "horizontal",
+ top: 65
+});
+var buttonRow3 = Ti.UI.createView({
+ height: Ti.UI.SIZE,
+ width: Ti.UI.SIZE,
+ layout: "horizontal",
+ bottom: 100
+});
-const win = Ti.UI.createWindow({
- backgroundColor: '#fff',
- title: 'Ti.Animation Demo'
- }),
- lbl = Ti.UI.createLabel({
- bottom: 50,
- color: '#000',
- textAlign: Ti.UI.TEXT_ALIGNMENT_CENTER,
- font: {
- fontSize: 12
- }
- }),
- view = TiAnimation.createAnimationView({
- file: 'sample_lottie_new_rendering_engine.json',
- loop: false,
- bottom: 200,
- left: 30,
- height: 120,
- width: 120,
- borderRadius: 60,
- autoStart: false
- }),
- view2 = TiAnimation.createAnimationView({
- file: 'sample_lottie.json',
- loop: true,
- bottom: 200,
- right: 30,
- height: 120,
- width: 120,
- borderRadius: 60,
- autoStart: true
- }),
- slider = Ti.UI.createSlider({
- value: 0,
- min: 0,
- max: 1,
- bottom: 10,
- width: 300
- });
+
+function onClickLoop(e) {
+ isLoop = !isLoop;
+ if (isLoop) {
+ e.source.backgroundColor = "#afa";
+ } else {
+ e.source.backgroundColor = "#fff";
+ }
+}
+
+
+buttonRow.add([
+ createButtonWithAction('Start', startAnimation),
+ createButtonWithAction('Pause', pauseAnimation),
+ createButtonWithAction('Resume', resumeAnimation),
+ createButtonWithAction('Stop/Reset', resetAnimation),
+]);
+buttonRow2.add([
+ createButtonWithAction('Loop', onClickLoop),
+]);
+buttonRow3.add([
+ createButtonWithAction('Double speed', doubleSpeed),
+ createButtonWithAction('Get frame', getFrame),
+]);
+
+const lbl_title = Ti.UI.createLabel({
+ bottom: 300,
+ color: "#000",
+ text: "Lottie:"
+});
+const lbl = Ti.UI.createLabel({
+ bottom: 40,
+ color: "#000",
+ textAlign: Ti.UI.TEXT_ALIGNMENT_CENTER,
+ font: {
+ fontSize: 12
+ }
+});
+const view = TiAnimation.createAnimationView({
+ file: '/sample_lottie.json',
+ loop: false,
+ bottom: 200,
+ left: 30,
+ height: 120,
+ width: 120,
+ borderRadius: 60,
+ autoStart: false
+});
+const view2 = TiAnimation.createAnimationView({
+ file: '/sample_lottie.json',
+ loop: false,
+ bottom: 200,
+ right: 30,
+ height: 120,
+ width: 120,
+ borderRadius: 60,
+ autoStart: true,
+ speed: 2,
+ loop: true
+});
+const riveView = TiAnimation.createAnimationView({
+ file: '/knight.riv',
+ top: 140,
+ height: 200,
+ width: 200,
+ animationType: TiAnimation.ANIMATION_RIVE,
+ //artboardName: "Main",
+ animationName: "idle",
+ //stateName: "idle"
+});
+const slider = Ti.UI.createSlider({
+ value: 0,
+ min: 0,
+ max: 1,
+ bottom: 10,
+ width: 300
+});
if (isAndroid) {
- view.addEventListener('update', function (e) {
- console.log('current frame: ' + e.frame);
+ view.addEventListener("update", function(e) {
+ console.log("current frame: " + e.frame)
});
}
-view.addEventListener('ready', function () {
+view.addEventListener("ready", function() {
var dur = (isAndroid) ? view.duration : (Math.floor(view.duration * 1000));
- lbl.text = 'Lottie: Duration: ' + dur + 'ms\n';
+ lbl.text = "Lottie: Duration: " + dur + "ms\n";
});
-view.addEventListener('complete', function () {
- console.log('view: complete');
+view.addEventListener("complete", function() {
+ console.log("view: complete");
});
-view2.addEventListener('complete', function () {
- console.log('view2: complete');
+view2.addEventListener("complete", function() {
+ console.log("view2: complete");
});
slider.addEventListener('change', seekToProgress);
win.add([
- view, view2, lbl, createButtonWithAction('Start animation', startAnimation), createButtonWithAction('Pause animation', pauseAnimation),
- createButtonWithAction('Resume animation', resumeAnimation), createButtonWithAction('Double speed', doubleSpeed), createButtonWithAction('Get frame', getFrame), slider
+ view, view2, riveView, lbl_title, lbl, buttonRow, slider, buttonRow2, buttonRow3
]);
-if (isAndroid) {
- win.open();
-} else {
- var nav = Ti.UI.createNavigationWindow({
- window: win
- });
- nav.open();
-}
+win.open();
+
+riveView.addEventListener("click", function() {
+ if (isDay) {
+ riveView.animationName = "day_night";
+ } else {
+ riveView.animationName = "night_day";
+ }
+ isDay = !isDay;
+})
function doubleSpeed(e) {
if (isDouble) {
- e.source.title = 'Double speed';
+ e.source.title = " Double speed ";
view.speed = 1;
} else {
- e.source.title = 'Normal speed';
+ e.source.title = "Normal speed";
view.speed = 2;
}
isDouble = !isDouble;
@@ -94,36 +161,47 @@ function seekToProgress(e) {
}
function getFrame() {
- console.log('Current frame view-animation: ' + view.frame);
+ console.log("Current frame view-animation: " + view.frame);
}
function createButtonWithAction(title, action) {
var btn = Ti.UI.createButton({
title: title,
- top: offset,
- height: 30,
- width: 200,
+ height: 50,
borderRadius: 4,
borderWidth: 1,
- borderColor: '#000',
- color: '#000',
- backgroundColor: '#fff'
+ right: 2,
+ borderColor: "#000",
+ color: "#000",
+ backgroundColor: "#eee",
+ touchFeedback: true,
+ touchFeedbackColor: "#aaa"
});
- btn.addEventListener('singletap', action);
+ btn.addEventListener('click', action);
- offset += 32;
return btn;
}
function startAnimation() {
+ view.loop = isLoop;
view.start();
+ riveView.start({
+ animationName: "idle",
+ loop: isLoop
+ });
+}
+
+function resetAnimation() {
+ riveView.reset();
}
function pauseAnimation() {
view.pause();
+ riveView.pause();
}
function resumeAnimation() {
view.resume();
+ riveView.resume();
}
diff --git a/example/knight.riv b/example/knight.riv
new file mode 100644
index 0000000..97bb9a3
Binary files /dev/null and b/example/knight.riv differ
diff --git a/example/vehicles.riv b/example/vehicles.riv
new file mode 100644
index 0000000..5574a91
Binary files /dev/null and b/example/vehicles.riv differ