feat:Android implement FillMode

This commit is contained in:
pengfei.zhou 2019-12-02 16:18:13 +08:00
parent 359e974424
commit 7f278073f3
4 changed files with 131 additions and 14 deletions

View File

@ -46,6 +46,7 @@ import com.github.pengfeizhou.jscore.JSDecoder;
import com.github.pengfeizhou.jscore.JSObject; import com.github.pengfeizhou.jscore.JSObject;
import com.github.pengfeizhou.jscore.JSValue; import com.github.pengfeizhou.jscore.JSValue;
import java.util.HashMap;
import java.util.LinkedList; import java.util.LinkedList;
/** /**
@ -663,9 +664,46 @@ public abstract class ViewNode<T extends View> extends DoricContextHolder {
JSValue animations = value.asObject().getProperty("animations"); JSValue animations = value.asObject().getProperty("animations");
if (animations.isArray()) { if (animations.isArray()) {
AnimatorSet animatorSet = new AnimatorSet(); AnimatorSet animatorSet = new AnimatorSet();
for (int i = 0; i < animations.asArray().size(); i++) { for (int i = 0; i < animations.asArray().size(); i++) {
animatorSet.play(parseAnimator(animations.asArray().get(i))); animatorSet.play(parseAnimator(animations.asArray().get(i)));
} }
JSValue delayJS = value.asObject().getProperty("delay");
if (delayJS.isNumber()) {
animatorSet.setStartDelay(delayJS.asNumber().toLong());
}
JSValue fillModeJSVal = value.asObject().getProperty("fillMode");
final int fillMode = fillModeJSVal.asNumber().toInt();
animatorSet.addListener(new AnimatorListenerAdapter() {
private HashMap<String, Float> originVals = new HashMap<>();
private String[] keys = {
"translationX",
"translationY",
"scaleX",
"scaleY",
"rotation",
};
@Override
public void onAnimationStart(Animator animation) {
super.onAnimationStart(animation);
for (String key : keys) {
originVals.put(key, getAnimatedValue(key));
}
}
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
if ((fillMode & 1) != 1) {
for (String key : keys) {
setAnimatedValue(key, originVals.get(key));
}
}
}
});
return animatorSet; return animatorSet;
} else if (value.isObject()) { } else if (value.isObject()) {
JSArray changeables = value.asObject().getProperty("changeables").asArray(); JSArray changeables = value.asObject().getProperty("changeables").asArray();
@ -674,9 +712,9 @@ public abstract class ViewNode<T extends View> extends DoricContextHolder {
JSValue repeatCount = value.asObject().getProperty("repeatCount"); JSValue repeatCount = value.asObject().getProperty("repeatCount");
JSValue repeatMode = value.asObject().getProperty("repeatMode"); JSValue repeatMode = value.asObject().getProperty("repeatMode");
JSValue fillMode = value.asObject().getProperty("fillMode");
for (int j = 0; j < changeables.size(); j++) { for (int j = 0; j < changeables.size(); j++) {
ObjectAnimator animator = parseChangeable(changeables.get(j).asObject()); ObjectAnimator animator = parseChangeable(changeables.get(j).asObject(), fillMode);
if (repeatCount.isNumber()) { if (repeatCount.isNumber()) {
animator.setRepeatCount(repeatCount.asNumber().toInt()); animator.setRepeatCount(repeatCount.asNumber().toInt());
} }
@ -698,12 +736,87 @@ public abstract class ViewNode<T extends View> extends DoricContextHolder {
} }
} }
private ObjectAnimator parseChangeable(JSObject jsObject) { private ObjectAnimator parseChangeable(JSObject jsObject, JSValue fillMode) {
String key = jsObject.getProperty("key").asString().value(); String key = jsObject.getProperty("key").asString().value();
return ObjectAnimator.ofFloat(this, float startVal = jsObject.getProperty("fromValue").asNumber().toFloat();
float endVal = jsObject.getProperty("toValue").asNumber().toFloat();
ObjectAnimator animator = ObjectAnimator.ofFloat(this,
key, key,
jsObject.getProperty("fromValue").asNumber().toFloat(), startVal,
jsObject.getProperty("toValue").asNumber().toFloat() endVal
); );
setFillMode(animator, key, startVal, endVal, fillMode);
return animator;
}
private void setFillMode(ObjectAnimator animator,
final String key,
float startVal,
float endVal,
JSValue jsValue) {
int fillMode = 0;
if (jsValue.isNumber()) {
fillMode = jsValue.asNumber().toInt();
}
if ((fillMode & 2) == 2) {
setAnimatedValue(key, startVal);
}
final int finalFillMode = fillMode;
animator.addListener(new AnimatorListenerAdapter() {
private float originVal;
@Override
public void onAnimationStart(Animator animation) {
super.onAnimationStart(animation);
originVal = getAnimatedValue(key);
}
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
if ((finalFillMode & 1) != 1) {
setAnimatedValue(key, originVal);
}
}
});
}
private void setAnimatedValue(String key, float value) {
switch (key) {
case "translationX":
setTranslationX(value);
break;
case "translationY":
setTranslationY(value);
break;
case "scaleX":
setScaleX(value);
break;
case "scaleY":
setScaleY(value);
break;
case "rotation":
setRotation(value);
break;
default:
break;
}
}
private float getAnimatedValue(String key) {
switch (key) {
case "translationX":
return getTranslationX();
case "translationY":
return getTranslationY();
case "scaleX":
return getScaleX();
case "scaleY":
return getScaleY();
case "rotation":
return getRotation();
default:
return 0;
}
} }
} }

View File

@ -170,8 +170,7 @@ class AnimatorDemo extends Panel {
thisLabel('animationSet').apply({ thisLabel('animationSet').apply({
onClick: () => { onClick: () => {
const animationSet = new AnimationSet const animationSet = new AnimationSet
animationSet.fillMode = FillMode.Forward //animationSet.fillMode = FillMode.Removed
animationSet.delay = 2000
const translate = new TranslationAnimation const translate = new TranslationAnimation
translate.fromTranslationX = 100 translate.fromTranslationX = 100
translate.toTranslationX = 200 translate.toTranslationX = 200
@ -179,6 +178,7 @@ class AnimatorDemo extends Panel {
translate.toTranslationY = 200 translate.toTranslationY = 200
translate.duration = 2000 translate.duration = 2000
translate.delay = 1000 translate.delay = 1000
translate.fillMode = FillMode.Forward
const scale = new ScaleAnimation const scale = new ScaleAnimation
scale.fromScaleX = 1 scale.fromScaleX = 1
scale.toScaleX = 5 scale.toScaleX = 5
@ -186,10 +186,12 @@ class AnimatorDemo extends Panel {
scale.toScaleY = 5 scale.toScaleY = 5
//scale.delay = 1000 //scale.delay = 1000
scale.duration = 2000 scale.duration = 2000
scale.fillMode = FillMode.Backward
const rotation = new RotationAnimation const rotation = new RotationAnimation
rotation.fromRotation = 0 rotation.fromRotation = 0
rotation.toRotation = 6.2 rotation.toRotation = 6.3
rotation.duration = 3000 rotation.duration = 2000
rotation.fillMode = FillMode.Removed
animationSet.addAnimation(translate) animationSet.addAnimation(translate)
animationSet.addAnimation(scale) animationSet.addAnimation(scale)
animationSet.addAnimation(rotation) animationSet.addAnimation(rotation)

View File

@ -340,7 +340,9 @@ - (CFTimeInterval)computeDurationOfAnimations:(NSArray<CAAnimation *> *)animatio
[animations forEach:^(CAAnimation *obj) { [animations forEach:^(CAAnimation *obj) {
interval = MAX(interval, obj.beginTime + obj.duration * (1 + obj.repeatCount)); interval = MAX(interval, obj.beginTime + obj.duration * (1 + obj.repeatCount));
}]; }];
return interval; /// Here add 0.00001 to force animationGroup's last child animation affects fill mode.
/// Otherwise the child's fill mode will be overwritten by parent.
return interval + 0.00001;
} }
- (CAAnimation *)parseAnimation:(id)params { - (CAAnimation *)parseAnimation:(id)params {

View File

@ -45,15 +45,15 @@ export enum FillMode {
/** /**
* The receiver remains visible in its final state when the animation is completed. * The receiver remains visible in its final state when the animation is completed.
*/ */
Forward = 1, Forward = 0x1,
/** /**
* The receiver clamps values before zero to zero when the animation is completed. * The receiver clamps values before zero to zero when the animation is completed.
*/ */
Backward = 2, Backward = 0x2,
/** /**
* The receiver clamps values at both ends of the objects time space * The receiver clamps values at both ends of the objects time space
*/ */
Both = 3, Both = 0x3,
} }
abstract class Animation implements IAnimation { abstract class Animation implements IAnimation {