feat:Add cancelAnimation and clearAnimation

This commit is contained in:
pengfei.zhou 2021-04-22 11:46:24 +08:00 committed by osborn
parent 15a62bad8a
commit e7ced92281
10 changed files with 132 additions and 94 deletions

View File

@ -920,20 +920,10 @@ public abstract class ViewNode<T extends View> extends DoricContextHolder {
if (animator != null) {
String animatorId = value.asObject().getProperty("id").asString().value();
animators.put(animatorId, animator);
// final float tx = getTranslationX();
// final float ty = getTranslationY();
// final float sx = getScaleX();
// final float sy = getScaleY();
// final float r = getRotation();
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationCancel(Animator animation) {
super.onAnimationCancel(animation);
// setTranslationX(tx);
// setTranslationY(ty);
// setScaleX(sx);
// setScaleY(sy);
// setRotation(r);
promise.reject(new JavaValue("Animation cancelled"));
}
@ -956,10 +946,8 @@ public abstract class ViewNode<T extends View> extends DoricContextHolder {
Animator animator = animators.get(id);
if (animator != null) {
animator.cancel();
promise.resolve();
} else {
promise.reject(new JavaValue("Cannot find running animation for " + id));
}
promise.resolve();
}
@DoricMethod
@ -967,10 +955,8 @@ public abstract class ViewNode<T extends View> extends DoricContextHolder {
Animator animator = animators.get(id);
if (animator != null) {
animator.cancel();
promise.resolve();
} else {
promise.reject(new JavaValue("Cannot find running animation for " + id));
}
promise.resolve();
}
private Animator parseAnimator(JSValue value) {

View File

@ -18,21 +18,30 @@ class Animations extends Panel {
height: 20,
backgroundColor: Color.BLUE,
}),
text({
text: "Start",
onClick: () => {
view.doAnimation(context, animation)
}
}),
text({
text: "Cancel",
onClick: () => {
view.cancelAnimation(context, animation)
}
}),
text({
text: "Clear",
onClick: () => {
view.clearAnimation(context, animation)
}
}),
],
{
space: 10,
space: 20,
layoutConfig: layoutConfig().most(),
gravity: Gravity.Center
}).in(root)

View File

@ -35,6 +35,10 @@ @interface AnimationCallback : NSObject <CAAnimationDelegate>
@property(nonatomic, strong) void (^startBlock)(AnimationCallback *callback);
@property(nonatomic, strong) void (^endBlock)(AnimationCallback *callback);
@property(nonatomic, strong) void (^cancelBlock)(void);
@property(nonatomic, strong) void (^clearBlock)(void);
@end
@implementation AnimationCallback
@ -507,37 +511,75 @@ - (NSDictionary *)transformation {
return dictionary;
}
- (void)setTransformation:(NSDictionary *)dictionary {
self.translationX = dictionary[@"translationX"];
self.translationY = dictionary[@"translationY"];
self.scaleX = dictionary[@"scaleX"];
self.scaleY = dictionary[@"scaleY"];
self.rotation = dictionary[@"rotation"];
};
#pragma animations
- (void)doAnimation:(id)params withPromise:(DoricPromise *)promise {
CAAnimation *animation = [self parseAnimation:params];
AnimationCallback *originDelegate = animation.delegate;
AnimationCallback *animationCallback = [[AnimationCallback new] also:^(AnimationCallback *it) {
__block BOOL stop = NO;
it.startBlock = ^(AnimationCallback *callback) {
if (originDelegate) {
originDelegate.startBlock(callback);
}
[self transformProperties];
};
it.endBlock = ^(AnimationCallback *callback) {
if (stop) {
return;
}
if (originDelegate) {
originDelegate.endBlock(callback);
}
[self.view.layer removeAllAnimations];
[self transformProperties];
[promise resolve:self.transformation];
};
it.cancelBlock = ^{
stop = YES;
self.view.layer.transform = self.view.layer.presentationLayer.transform;
[promise reject:@"Animation cancelled"];
};
it.clearBlock = ^{
stop = YES;
[promise reject:@"Animation cleared"];
};
}];
animation.delegate = animationCallback;
if (params[@"delay"]) {
animation.beginTime = CACurrentMediaTime() + [params[@"delay"] floatValue] / 1000;
}
animation.removedOnCompletion = NO;
animation.removedOnCompletion = YES;
animation.fillMode = kCAFillModeForwards;
if (animation.duration == 0) {
animation.duration = FLT_MIN;
}
[self.view.layer addAnimation:animation forKey:nil];
[self.view.layer addAnimation:animation forKey:params[@"id"]];
}
- (void)clearAnimation:(NSString *)animationId withPromise:(DoricPromise *)promise {
CAAnimation *caAnimation = [self.view.layer animationForKey:animationId];
if ([caAnimation.delegate isKindOfClass:AnimationCallback.class]) {
((AnimationCallback *) caAnimation.delegate).clearBlock();
}
[self.view.layer removeAnimationForKey:animationId];
[promise resolve:nil];
}
- (void)cancelAnimation:(NSString *)animationId withPromise:(DoricPromise *)promise {
CAAnimation *caAnimation = [self.view.layer animationForKey:animationId];
if ([caAnimation.delegate isKindOfClass:AnimationCallback.class]) {
((AnimationCallback *) caAnimation.delegate).cancelBlock();
}
[self.view.layer removeAnimationForKey:animationId];
[promise resolve:nil];
}
- (CFTimeInterval)computeDurationOfAnimations:(NSArray<CAAnimation *> *)animations {
@ -584,40 +626,6 @@ - (CAAnimation *)parseAnimation:(id)params {
return animationGroup;
} else if ([params isKindOfClass:[NSDictionary class]]) {
NSArray<NSDictionary *> *changeables = params[@"changeables"];
NSString *type = params[@"type"];
if ([@"TranslationAnimation" isEqualToString:type]) {
__block CGPoint from = self.view.layer.position;
__block CGPoint to = self.view.layer.position;
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
[changeables forEach:^(NSDictionary *obj) {
NSString *key = obj[@"key"];
if ([@"translationX" isEqualToString:key]) {
from.x += [obj[@"fromValue"] floatValue] - self.translationX.floatValue;
to.x += [obj[@"toValue"] floatValue] - self.translationX.floatValue;
[self setFillMode:animation
key:key
startValue:obj[@"fromValue"]
endValue:obj[@"toValue"]
fillMode:params[@"fillMode"]];
} else if ([@"translationY" isEqualToString:key]) {
from.y += [obj[@"fromValue"] floatValue] - self.translationY.floatValue;
to.y += [obj[@"toValue"] floatValue] - self.translationY.floatValue;
[self setFillMode:animation
key:key
startValue:obj[@"fromValue"]
endValue:obj[@"toValue"]
fillMode:params[@"fillMode"]];
}
}];
animation.fromValue = [NSValue valueWithCGPoint:from];
animation.toValue = [NSValue valueWithCGPoint:to];
if (params[@"timingFunction"]) {
animation.timingFunction = [self translateToTimingFunction:params[@"timingFunction"]];
}
[self setAnimation:animation params:params];
return animation;
} else {
CAAnimationGroup *animationGroup = [CAAnimationGroup animation];
NSMutableArray <CABasicAnimation *> *animations = [NSMutableArray new];
@ -652,7 +660,6 @@ - (CAAnimation *)parseAnimation:(id)params {
[self setAnimation:animationGroup params:params];
return animationGroup;
}
}
return nil;
}
@ -752,7 +759,15 @@ - (void)setAnimatedValue:(NSString *)key value:(NSNumber *)value {
- (CABasicAnimation *)parseChangeable:(NSDictionary *)params fillMode:(NSNumber *)fillMode {
NSString *key = params[@"key"];
CABasicAnimation *animation = [CABasicAnimation animation];
if ([@"scaleX" isEqualToString:key]) {
if ([@"translationX" isEqualToString:key]) {
animation.keyPath = @"transform.translation.x";
animation.fromValue = params[@"fromValue"];
animation.toValue = params[@"toValue"];
} else if ([@"translationY" isEqualToString:key]) {
animation.keyPath = @"transform.translation.y";
animation.fromValue = params[@"fromValue"];
animation.toValue = params[@"toValue"];
} else if ([@"scaleX" isEqualToString:key]) {
animation.keyPath = @"transform.scale.x";
animation.fromValue = params[@"fromValue"];
animation.toValue = params[@"toValue"];

View File

@ -399,6 +399,19 @@ var View = /** @class */ (function () {
}
});
};
View.prototype.clearAnimation = function (context, animation) {
var _this = this;
return this.nativeChannel(context, "clearAnimation")(animation.id).then(function () {
_this.__dirty_props__.translationX = _this.translationX || 0;
_this.__dirty_props__.translationY = _this.translationY || 0;
_this.__dirty_props__.scaleX = _this.scaleX || 1;
_this.__dirty_props__.scaleY = _this.scaleY || 1;
_this.__dirty_props__.rotation = _this.rotation || 0;
});
};
View.prototype.cancelAnimation = function (context, animation) {
return this.nativeChannel(context, "cancelAnimation")(animation.id);
};
__decorate$d([
Property,
__metadata$d("design:type", Number)

View File

@ -314,8 +314,8 @@ class View {
}
});
}
cancelAnimation(context, animation) {
return this.nativeChannel(context, "cancelAnimation")(animation.id).then(() => {
clearAnimation(context, animation) {
return this.nativeChannel(context, "clearAnimation")(animation.id).then(() => {
this.__dirty_props__.translationX = this.translationX || 0;
this.__dirty_props__.translationY = this.translationY || 0;
this.__dirty_props__.scaleX = this.scaleX || 1;
@ -323,6 +323,9 @@ class View {
this.__dirty_props__.rotation = this.rotation || 0;
});
}
cancelAnimation(context, animation) {
return this.nativeChannel(context, "cancelAnimation")(animation.id);
}
}
__decorate$d([
Property,

View File

@ -1835,8 +1835,8 @@ class View {
}
});
}
cancelAnimation(context, animation) {
return this.nativeChannel(context, "cancelAnimation")(animation.id).then(() => {
clearAnimation(context, animation) {
return this.nativeChannel(context, "clearAnimation")(animation.id).then(() => {
this.__dirty_props__.translationX = this.translationX || 0;
this.__dirty_props__.translationY = this.translationY || 0;
this.__dirty_props__.scaleX = this.scaleX || 1;
@ -1844,6 +1844,9 @@ class View {
this.__dirty_props__.rotation = this.rotation || 0;
});
}
cancelAnimation(context, animation) {
return this.nativeChannel(context, "cancelAnimation")(animation.id);
}
}
__decorate$d([
Property,

3
doric-js/index.d.ts vendored
View File

@ -298,7 +298,8 @@ declare module 'doric/lib/src/ui/view' {
*/
flexConfig?: FlexConfig;
doAnimation(context: BridgeContext, animation: IAnimation): Promise<void>;
cancelAnimation(context: BridgeContext, animation: IAnimation): Promise<void>;
clearAnimation(context: BridgeContext, animation: IAnimation): Promise<void>;
cancelAnimation(context: BridgeContext, animation: IAnimation): Promise<any>;
}
export abstract class Superview extends View {
subviewById(id: string): View | undefined;

View File

@ -130,7 +130,8 @@ export declare abstract class View implements Modeling {
*/
flexConfig?: FlexConfig;
doAnimation(context: BridgeContext, animation: IAnimation): Promise<void>;
cancelAnimation(context: BridgeContext, animation: IAnimation): Promise<void>;
clearAnimation(context: BridgeContext, animation: IAnimation): Promise<void>;
cancelAnimation(context: BridgeContext, animation: IAnimation): Promise<any>;
}
export declare abstract class Superview extends View {
subviewById(id: string): View | undefined;

View File

@ -199,8 +199,8 @@ export class View {
}
});
}
cancelAnimation(context, animation) {
return this.nativeChannel(context, "cancelAnimation")(animation.id).then(() => {
clearAnimation(context, animation) {
return this.nativeChannel(context, "clearAnimation")(animation.id).then(() => {
this.__dirty_props__.translationX = this.translationX || 0;
this.__dirty_props__.translationY = this.translationY || 0;
this.__dirty_props__.scaleX = this.scaleX || 1;
@ -208,6 +208,9 @@ export class View {
this.__dirty_props__.rotation = this.rotation || 0;
});
}
cancelAnimation(context, animation) {
return this.nativeChannel(context, "cancelAnimation")(animation.id);
}
}
__decorate([
Property,

View File

@ -352,6 +352,10 @@ export abstract class View implements Modeling {
this.__dirty_props__.rotation = this.rotation || 0
})
}
cancelAnimation(context: BridgeContext, animation: IAnimation) {
return this.nativeChannel(context, "cancelAnimation")(animation.id)
}
}
export abstract class Superview extends View {