Merge branch 'feature/animation' into 'master'

Feature/animation



See merge request !40
This commit is contained in:
pengfeizhou 2019-12-02 19:59:38 +08:00
commit f22b4a1cde
7 changed files with 120 additions and 25 deletions

View File

@ -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();

View File

@ -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([

View File

@ -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([

View File

@ -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
}, },
}) })
} }

View File

@ -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];
} }
} }

View File

@ -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
} }
} }
} }

View File

@ -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