Merge branch 'feature/animation' into 'master'
Feature/animation See merge request !40
This commit is contained in:
commit
f22b4a1cde
@ -25,10 +25,17 @@ import android.graphics.Color;
|
|||||||
import android.graphics.drawable.ColorDrawable;
|
import android.graphics.drawable.ColorDrawable;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
import android.view.animation.AccelerateDecelerateInterpolator;
|
||||||
|
import android.view.animation.AccelerateInterpolator;
|
||||||
|
import android.view.animation.DecelerateInterpolator;
|
||||||
|
import android.view.animation.Interpolator;
|
||||||
|
import android.view.animation.LinearInterpolator;
|
||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.interpolator.view.animation.FastOutSlowInInterpolator;
|
||||||
|
import androidx.interpolator.view.animation.LinearOutSlowInInterpolator;
|
||||||
|
|
||||||
import pub.doric.DoricContext;
|
import pub.doric.DoricContext;
|
||||||
import pub.doric.DoricRegistry;
|
import pub.doric.DoricRegistry;
|
||||||
@ -695,6 +702,7 @@ public abstract class ViewNode<T extends View> extends DoricContextHolder {
|
|||||||
|
|
||||||
JSValue repeatMode = value.asObject().getProperty("repeatMode");
|
JSValue repeatMode = value.asObject().getProperty("repeatMode");
|
||||||
JSValue fillMode = value.asObject().getProperty("fillMode");
|
JSValue fillMode = value.asObject().getProperty("fillMode");
|
||||||
|
JSValue timingFunction = value.asObject().getProperty("timingFunction");
|
||||||
for (int j = 0; j < changeables.size(); j++) {
|
for (int j = 0; j < changeables.size(); j++) {
|
||||||
ObjectAnimator animator = parseChangeable(changeables.get(j).asObject(), fillMode);
|
ObjectAnimator animator = parseChangeable(changeables.get(j).asObject(), fillMode);
|
||||||
if (repeatCount.isNumber()) {
|
if (repeatCount.isNumber()) {
|
||||||
@ -703,6 +711,9 @@ public abstract class ViewNode<T extends View> extends DoricContextHolder {
|
|||||||
if (repeatMode.isNumber()) {
|
if (repeatMode.isNumber()) {
|
||||||
animator.setRepeatMode(repeatMode.asNumber().toInt());
|
animator.setRepeatMode(repeatMode.asNumber().toInt());
|
||||||
}
|
}
|
||||||
|
if (timingFunction.isNumber()) {
|
||||||
|
animator.setInterpolator(getTimingInterpolator(timingFunction.asNumber().toInt()));
|
||||||
|
}
|
||||||
animatorSet.play(animator);
|
animatorSet.play(animator);
|
||||||
}
|
}
|
||||||
long duration = value.asObject().getProperty("duration").asNumber().toLong();
|
long duration = value.asObject().getProperty("duration").asNumber().toLong();
|
||||||
@ -711,13 +722,27 @@ public abstract class ViewNode<T extends View> extends DoricContextHolder {
|
|||||||
if (delayJS.isNumber()) {
|
if (delayJS.isNumber()) {
|
||||||
animatorSet.setStartDelay(delayJS.asNumber().toLong());
|
animatorSet.setStartDelay(delayJS.asNumber().toLong());
|
||||||
}
|
}
|
||||||
|
|
||||||
return animatorSet;
|
return animatorSet;
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Interpolator getTimingInterpolator(int timingFunction) {
|
||||||
|
switch (timingFunction) {
|
||||||
|
case 1:
|
||||||
|
return new LinearInterpolator();
|
||||||
|
case 2:
|
||||||
|
return new AccelerateInterpolator();
|
||||||
|
case 3:
|
||||||
|
return new DecelerateInterpolator();
|
||||||
|
case 4:
|
||||||
|
return new FastOutSlowInInterpolator();
|
||||||
|
default:
|
||||||
|
return new AccelerateDecelerateInterpolator();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private ObjectAnimator parseChangeable(JSObject jsObject, JSValue fillMode) {
|
private ObjectAnimator parseChangeable(JSObject jsObject, JSValue fillMode) {
|
||||||
String key = jsObject.getProperty("key").asString().value();
|
String key = jsObject.getProperty("key").asString().value();
|
||||||
float startVal = jsObject.getProperty("fromValue").asNumber().toFloat();
|
float startVal = jsObject.getProperty("fromValue").asNumber().toFloat();
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { animate, Group, Panel, gravity, Color, AnimationSet, vlayout, scroller, layoutConfig, IVLayout, modal, IText, network, View, stack, IHLayout, hlayout, IView, text, TranslationAnimation, ScaleAnimation, RotationAnimation, FillMode } from "doric";
|
import { animate, Group, Panel, gravity, Color, AnimationSet, vlayout, scroller, layoutConfig, IVLayout, modal, IText, network, View, stack, IHLayout, hlayout, IView, text, TranslationAnimation, ScaleAnimation, RotationAnimation, FillMode, TimingFunction } from "doric";
|
||||||
import { title, colors, box } from "./utils";
|
import { title, colors, box } from "./utils";
|
||||||
|
|
||||||
function thisLabel(str: string) {
|
function thisLabel(str: string) {
|
||||||
@ -122,6 +122,58 @@ class AnimationDemo extends Panel {
|
|||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
]).apply({ space: 10 } as IHLayout),
|
]).apply({ space: 10 } as IHLayout),
|
||||||
|
hlayout([
|
||||||
|
thisLabel('Default').apply({
|
||||||
|
onClick: () => {
|
||||||
|
const translation = new TranslationAnimation
|
||||||
|
translation.duration = 3000
|
||||||
|
translation.fromTranslationX = 0
|
||||||
|
translation.toTranslationX = 300
|
||||||
|
translation.timingFunction = TimingFunction.Default
|
||||||
|
view.doAnimation(context, translation)
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
thisLabel('Linear').apply({
|
||||||
|
onClick: () => {
|
||||||
|
const translation = new TranslationAnimation
|
||||||
|
translation.duration = 3000
|
||||||
|
translation.fromTranslationX = 0
|
||||||
|
translation.toTranslationX = 300
|
||||||
|
translation.timingFunction = TimingFunction.Linear
|
||||||
|
view.doAnimation(context, translation)
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
thisLabel('EaseIn').apply({
|
||||||
|
onClick: () => {
|
||||||
|
const translation = new TranslationAnimation
|
||||||
|
translation.duration = 3000
|
||||||
|
translation.fromTranslationX = 0
|
||||||
|
translation.toTranslationX = 300
|
||||||
|
translation.timingFunction = TimingFunction.EaseIn
|
||||||
|
view.doAnimation(context, translation)
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
thisLabel('EaseOut').apply({
|
||||||
|
onClick: () => {
|
||||||
|
const translation = new TranslationAnimation
|
||||||
|
translation.duration = 3000
|
||||||
|
translation.fromTranslationX = 0
|
||||||
|
translation.toTranslationX = 300
|
||||||
|
translation.timingFunction = TimingFunction.EaseOut
|
||||||
|
view.doAnimation(context, translation)
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
thisLabel('EaseInEaseOut').apply({
|
||||||
|
onClick: () => {
|
||||||
|
const translation = new TranslationAnimation
|
||||||
|
translation.duration = 3000
|
||||||
|
translation.fromTranslationX = 0
|
||||||
|
translation.toTranslationX = 300
|
||||||
|
translation.timingFunction = TimingFunction.EaseInEaseOut
|
||||||
|
view.doAnimation(context, translation)
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
]).apply({ space: 10 } as IHLayout),
|
||||||
]
|
]
|
||||||
).apply({ space: 10 } as IVLayout),
|
).apply({ space: 10 } as IVLayout),
|
||||||
stack([
|
stack([
|
||||||
|
@ -32,7 +32,7 @@ class RefreshableDemo extends Panel {
|
|||||||
log('stopAnimation')
|
log('stopAnimation')
|
||||||
},
|
},
|
||||||
setProgressRotation: (rotation: number) => {
|
setProgressRotation: (rotation: number) => {
|
||||||
refreshImage.setRotation(context, rotation)
|
refreshImage.rotation = rotation
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
content: (vlayout([
|
content: (vlayout([
|
||||||
|
@ -66,7 +66,7 @@ export function rotatedArrow(context: BridgeContext) {
|
|||||||
log('stopAnimation')
|
log('stopAnimation')
|
||||||
},
|
},
|
||||||
setProgressRotation: (rotation: number) => {
|
setProgressRotation: (rotation: number) => {
|
||||||
refreshImage.setRotation(context, rotation)
|
refreshImage.rotation = rotation
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
@ -454,6 +454,9 @@ - (CAAnimation *)parseAnimation:(id)params {
|
|||||||
}];
|
}];
|
||||||
animation.fromValue = [NSValue valueWithCGPoint:from];
|
animation.fromValue = [NSValue valueWithCGPoint:from];
|
||||||
animation.toValue = [NSValue valueWithCGPoint:to];
|
animation.toValue = [NSValue valueWithCGPoint:to];
|
||||||
|
if (params[@"timingFunction"]) {
|
||||||
|
animation.timingFunction = [self translateToTimingFunction:params[@"timingFunction"]];
|
||||||
|
}
|
||||||
[self setAnimation:animation params:params];
|
[self setAnimation:animation params:params];
|
||||||
return animation;
|
return animation;
|
||||||
} else {
|
} else {
|
||||||
@ -462,6 +465,9 @@ - (CAAnimation *)parseAnimation:(id)params {
|
|||||||
|
|
||||||
[changeables forEach:^(NSDictionary *obj) {
|
[changeables forEach:^(NSDictionary *obj) {
|
||||||
CABasicAnimation *animation = [self parseChangeable:obj fillMode:params[@"fillMode"]];
|
CABasicAnimation *animation = [self parseChangeable:obj fillMode:params[@"fillMode"]];
|
||||||
|
if (params[@"timingFunction"]) {
|
||||||
|
animation.timingFunction = [self translateToTimingFunction:params[@"timingFunction"]];
|
||||||
|
}
|
||||||
[animations addObject:animation];
|
[animations addObject:animation];
|
||||||
}];
|
}];
|
||||||
animationGroup.animations = animations;
|
animationGroup.animations = animations;
|
||||||
@ -603,16 +609,18 @@ - (CABasicAnimation *)parseChangeable:(NSDictionary *)params fillMode:(NSNumber
|
|||||||
return animation;
|
return animation;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CAMediaTimingFillMode)translateToFillMode:(NSNumber *)fillMode {
|
- (CAMediaTimingFunction *)translateToTimingFunction:(NSNumber *)timingFunction {
|
||||||
switch ([fillMode integerValue]) {
|
switch (timingFunction.integerValue) {
|
||||||
case 1:
|
case 1:
|
||||||
return kCAFillModeForwards;
|
return [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
|
||||||
case 2:
|
case 2:
|
||||||
return kCAFillModeBackwards;
|
return [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
|
||||||
case 3:
|
case 3:
|
||||||
return kCAFillModeBoth;
|
return [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
|
||||||
|
case 4:
|
||||||
|
return [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
|
||||||
default:
|
default:
|
||||||
return kCAFillModeRemoved;
|
return [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,6 +55,29 @@ export enum FillMode {
|
|||||||
Both = 0x3,
|
Both = 0x3,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum TimingFunction {
|
||||||
|
/**
|
||||||
|
* The system default timing function. Use this function to ensure that the timing of your animations matches that of most system animations.
|
||||||
|
*/
|
||||||
|
Default = 0,
|
||||||
|
/**
|
||||||
|
* Linear pacing, which causes an animation to occur evenly over its duration.
|
||||||
|
*/
|
||||||
|
Linear,
|
||||||
|
/**
|
||||||
|
* Ease-in pacing, which causes an animation to begin slowly and then speed up as it progresses.
|
||||||
|
*/
|
||||||
|
EaseIn,
|
||||||
|
/**
|
||||||
|
* Ease-out pacing, which causes an animation to begin quickly and then slow as it progresses.
|
||||||
|
*/
|
||||||
|
EaseOut,
|
||||||
|
/**
|
||||||
|
* Ease-in-ease-out pacing, which causes an animation to begin slowly, accelerate through the middle of its duration, and then slow again before completing.
|
||||||
|
*/
|
||||||
|
EaseInEaseOut,
|
||||||
|
}
|
||||||
|
|
||||||
abstract class Animation implements IAnimation {
|
abstract class Animation implements IAnimation {
|
||||||
changeables: Map<AnimatedKey, Changeable> = new Map
|
changeables: Map<AnimatedKey, Changeable> = new Map
|
||||||
duration = 0
|
duration = 0
|
||||||
@ -62,6 +85,7 @@ abstract class Animation implements IAnimation {
|
|||||||
repeatMode?: RepeatMode
|
repeatMode?: RepeatMode
|
||||||
delay?: number
|
delay?: number
|
||||||
fillMode = FillMode.Forward
|
fillMode = FillMode.Forward
|
||||||
|
timingFunction?: TimingFunction
|
||||||
toModel() {
|
toModel() {
|
||||||
const changeables = []
|
const changeables = []
|
||||||
for (let e of this.changeables.values()) {
|
for (let e of this.changeables.values()) {
|
||||||
@ -79,6 +103,7 @@ abstract class Animation implements IAnimation {
|
|||||||
repeatCount: this.repeatCount,
|
repeatCount: this.repeatCount,
|
||||||
repeatMode: this.repeatMode,
|
repeatMode: this.repeatMode,
|
||||||
fillMode: this.fillMode,
|
fillMode: this.fillMode,
|
||||||
|
timingFunction: this.timingFunction
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -297,21 +297,6 @@ export abstract class View implements Modeling, IView {
|
|||||||
return this.nativeChannel(context, 'getHeight')() as Promise<number>
|
return this.nativeChannel(context, 'getHeight')() as Promise<number>
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param rotation [0..1]
|
|
||||||
*/
|
|
||||||
setRotation(context: BridgeContext, rotation: number) {
|
|
||||||
return this.nativeChannel(context, 'setRotation')(rotation)
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @return rotation [0..1]
|
|
||||||
*/
|
|
||||||
getRotation(context: BridgeContext) {
|
|
||||||
return this.nativeChannel(context, 'getRotation')() as Promise<number>
|
|
||||||
}
|
|
||||||
|
|
||||||
/**++++++++++transform++++++++++*/
|
/**++++++++++transform++++++++++*/
|
||||||
@Property
|
@Property
|
||||||
translationX?: number
|
translationX?: number
|
||||||
|
Reference in New Issue
Block a user