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

View File

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

View File

@ -35,6 +35,10 @@ @interface AnimationCallback : NSObject <CAAnimationDelegate>
@property(nonatomic, strong) void (^startBlock)(AnimationCallback *callback); @property(nonatomic, strong) void (^startBlock)(AnimationCallback *callback);
@property(nonatomic, strong) void (^endBlock)(AnimationCallback *callback); @property(nonatomic, strong) void (^endBlock)(AnimationCallback *callback);
@property(nonatomic, strong) void (^cancelBlock)(void);
@property(nonatomic, strong) void (^clearBlock)(void);
@end @end
@implementation AnimationCallback @implementation AnimationCallback
@ -507,37 +511,75 @@ - (NSDictionary *)transformation {
return dictionary; 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 #pragma animations
- (void)doAnimation:(id)params withPromise:(DoricPromise *)promise { - (void)doAnimation:(id)params withPromise:(DoricPromise *)promise {
CAAnimation *animation = [self parseAnimation:params]; CAAnimation *animation = [self parseAnimation:params];
AnimationCallback *originDelegate = animation.delegate; AnimationCallback *originDelegate = animation.delegate;
AnimationCallback *animationCallback = [[AnimationCallback new] also:^(AnimationCallback *it) { AnimationCallback *animationCallback = [[AnimationCallback new] also:^(AnimationCallback *it) {
__block BOOL stop = NO;
it.startBlock = ^(AnimationCallback *callback) { it.startBlock = ^(AnimationCallback *callback) {
if (originDelegate) { if (originDelegate) {
originDelegate.startBlock(callback); originDelegate.startBlock(callback);
} }
[self transformProperties];
}; };
it.endBlock = ^(AnimationCallback *callback) { it.endBlock = ^(AnimationCallback *callback) {
if (stop) {
return;
}
if (originDelegate) { if (originDelegate) {
originDelegate.endBlock(callback); originDelegate.endBlock(callback);
} }
[self.view.layer removeAllAnimations];
[self transformProperties]; [self transformProperties];
[promise resolve:self.transformation]; [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; animation.delegate = animationCallback;
if (params[@"delay"]) { if (params[@"delay"]) {
animation.beginTime = CACurrentMediaTime() + [params[@"delay"] floatValue] / 1000; animation.beginTime = CACurrentMediaTime() + [params[@"delay"] floatValue] / 1000;
} }
animation.removedOnCompletion = NO; animation.removedOnCompletion = YES;
animation.fillMode = kCAFillModeForwards; animation.fillMode = kCAFillModeForwards;
if (animation.duration == 0) { if (animation.duration == 0) {
animation.duration = FLT_MIN; 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 { - (CFTimeInterval)computeDurationOfAnimations:(NSArray<CAAnimation *> *)animations {
@ -584,40 +626,6 @@ - (CAAnimation *)parseAnimation:(id)params {
return animationGroup; return animationGroup;
} else if ([params isKindOfClass:[NSDictionary class]]) { } else if ([params isKindOfClass:[NSDictionary class]]) {
NSArray<NSDictionary *> *changeables = params[@"changeables"]; 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]; CAAnimationGroup *animationGroup = [CAAnimationGroup animation];
NSMutableArray <CABasicAnimation *> *animations = [NSMutableArray new]; NSMutableArray <CABasicAnimation *> *animations = [NSMutableArray new];
@ -652,7 +660,6 @@ - (CAAnimation *)parseAnimation:(id)params {
[self setAnimation:animationGroup params:params]; [self setAnimation:animationGroup params:params];
return animationGroup; return animationGroup;
} }
}
return nil; return nil;
} }
@ -752,7 +759,15 @@ - (void)setAnimatedValue:(NSString *)key value:(NSNumber *)value {
- (CABasicAnimation *)parseChangeable:(NSDictionary *)params fillMode:(NSNumber *)fillMode { - (CABasicAnimation *)parseChangeable:(NSDictionary *)params fillMode:(NSNumber *)fillMode {
NSString *key = params[@"key"]; NSString *key = params[@"key"];
CABasicAnimation *animation = [CABasicAnimation animation]; 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.keyPath = @"transform.scale.x";
animation.fromValue = params[@"fromValue"]; animation.fromValue = params[@"fromValue"];
animation.toValue = params[@"toValue"]; 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([ __decorate$d([
Property, Property,
__metadata$d("design:type", Number) __metadata$d("design:type", Number)

View File

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

View File

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

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

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

View File

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

View File

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

View File

@ -352,6 +352,10 @@ export abstract class View implements Modeling {
this.__dirty_props__.rotation = this.rotation || 0 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 { export abstract class Superview extends View {