This repository has been archived on 2024-07-22. You can view files and clone it, but cannot push or open issues or pull requests.
Doric/iOS/Pod/Classes/Shader/DoricViewNode.m

620 lines
22 KiB
Mathematica
Raw Normal View History

2019-10-21 09:59:22 +08:00
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
2019-07-30 15:20:11 +08:00
//
// DoricViewNode.m
// Doric
//
// Created by pengfei.zhou on 2019/7/30.
//
#import "DoricViewNode.h"
#import "DoricUtil.h"
#import "DoricGroupNode.h"
2019-07-30 21:05:27 +08:00
#import "DoricRootNode.h"
#import "DoricConstant.h"
2019-11-15 14:57:41 +08:00
#import "DoricSuperNode.h"
#import "DoricExtensions.h"
2019-11-30 18:30:46 +08:00
#import "DoricPromise.h"
2019-07-30 15:20:11 +08:00
2019-08-02 20:24:05 +08:00
void DoricAddEllipticArcPath(CGMutablePathRef path,
2019-10-12 14:48:19 +08:00
CGPoint origin,
CGFloat radius,
CGFloat startAngle,
CGFloat endAngle) {
2019-08-02 20:24:05 +08:00
CGAffineTransform t = CGAffineTransformMakeTranslation(origin.x, origin.y);
CGPathAddArc(path, &t, 0, 0, radius, startAngle, endAngle, NO);
}
CGPathRef DoricCreateRoundedRectPath(CGRect bounds,
2019-10-12 14:48:19 +08:00
CGFloat leftTop,
CGFloat rightTop,
CGFloat rightBottom,
CGFloat leftBottom) {
2019-08-02 20:24:05 +08:00
const CGFloat minX = CGRectGetMinX(bounds);
const CGFloat minY = CGRectGetMinY(bounds);
const CGFloat maxX = CGRectGetMaxX(bounds);
const CGFloat maxY = CGRectGetMaxY(bounds);
2019-10-12 14:48:19 +08:00
2019-08-02 20:24:05 +08:00
CGMutablePathRef path = CGPathCreateMutable();
2019-10-12 14:48:19 +08:00
DoricAddEllipticArcPath(path, (CGPoint) {
minX + leftTop, minY + leftTop
2019-08-02 20:24:05 +08:00
}, leftTop, M_PI, 3 * M_PI_2);
2019-10-12 14:48:19 +08:00
DoricAddEllipticArcPath(path, (CGPoint) {
maxX - rightTop, minY + rightTop
2019-08-02 20:24:05 +08:00
}, rightTop, 3 * M_PI_2, 0);
2019-10-12 14:48:19 +08:00
DoricAddEllipticArcPath(path, (CGPoint) {
maxX - rightBottom, maxY - rightBottom
2019-08-02 20:24:05 +08:00
}, rightBottom, 0, M_PI_2);
2019-10-12 14:48:19 +08:00
DoricAddEllipticArcPath(path, (CGPoint) {
minX + leftBottom, maxY - leftBottom
2019-08-02 20:24:05 +08:00
}, leftBottom, M_PI_2, M_PI);
CGPathCloseSubpath(path);
return path;
}
2019-12-02 11:07:45 +08:00
@interface AnimationCallback : NSObject <CAAnimationDelegate>
2019-12-02 18:07:03 +08:00
@property(nonatomic, strong) NSMutableDictionary *dictionary;
@property(nonatomic, strong) void (^startBlock)(AnimationCallback *callback);
@property(nonatomic, strong) void (^endBlock)(AnimationCallback *callback);
2019-12-02 11:07:45 +08:00
@end
@implementation AnimationCallback
2019-12-02 18:07:03 +08:00
- (instancetype)init {
if (self = [super init]) {
_dictionary = [NSMutableDictionary new];
}
return self;
}
- (void)animationDidStart:(CAAnimation *)anim {
if (self.startBlock) {
self.startBlock(self);
}
}
2019-12-02 11:07:45 +08:00
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
if (self.endBlock) {
2019-12-02 18:07:03 +08:00
self.endBlock(self);
2019-12-02 11:07:45 +08:00
}
}
@end
2019-08-02 20:24:05 +08:00
2019-10-12 14:48:19 +08:00
@interface DoricViewNode ()
@property(nonatomic, strong) NSMutableDictionary *callbackIds;
2019-11-29 19:17:02 +08:00
@property(nonatomic, copy) NSNumber *translationX;
@property(nonatomic, copy) NSNumber *translationY;
@property(nonatomic, copy) NSNumber *scaleX;
@property(nonatomic, copy) NSNumber *scaleY;
@property(nonatomic, copy) NSNumber *rotation;
@property(nonatomic, copy) NSNumber *pivotX;
@property(nonatomic, copy) NSNumber *pivotY;
2019-07-31 19:22:00 +08:00
@end
2019-07-30 15:20:11 +08:00
@implementation DoricViewNode
2019-07-31 19:22:00 +08:00
- (instancetype)initWithContext:(DoricContext *)doricContext {
2019-10-12 14:48:19 +08:00
if (self = [super initWithContext:doricContext]) {
2019-07-31 19:22:00 +08:00
_callbackIds = [[NSMutableDictionary alloc] init];
}
return self;
}
2019-10-12 14:48:19 +08:00
2019-11-15 14:57:41 +08:00
- (void)initWithSuperNode:(DoricSuperNode *)superNode {
2019-11-19 11:21:49 +08:00
if ([self isKindOfClass:[DoricSuperNode class]]) {
((DoricSuperNode *) self).reusable = superNode.reusable;
}
2019-11-15 14:57:41 +08:00
self.superNode = superNode;
self.view = [[self build] also:^(UIView *it) {
it.layoutConfig = [superNode generateDefaultLayoutParams];
}];
}
- (DoricLayoutConfig *)layoutConfig {
return self.view.layoutConfig;
}
- (UIView *)build {
2019-07-30 15:20:11 +08:00
return [[UIView alloc] init];
}
- (void)blend:(NSDictionary *)props {
self.view.layoutConfig = self.layoutConfig;
2019-07-30 15:20:11 +08:00
for (NSString *key in props) {
id value = props[key];
[self blendView:self.view forPropName:key propValue:value];
}
2019-11-29 19:17:02 +08:00
[self transformProperties];
}
- (void)transformProperties {
CGAffineTransform transform = CGAffineTransformIdentity;
if (self.translationX || self.translationY) {
transform = CGAffineTransformTranslate(transform, [self.translationX floatValue] ?: 0, [self.translationY floatValue] ?: 0);
}
if (self.scaleX || self.scaleY) {
transform = CGAffineTransformScale(transform, [self.scaleX floatValue] ?: 1, [self.scaleY floatValue] ?: 1);
}
if (self.rotation) {
transform = CGAffineTransformRotate(transform, (self.rotation.floatValue ?: 0) * M_PI);
}
if (!CGAffineTransformEqualToTransform(transform, self.view.transform)) {
self.view.transform = transform;
}
if (self.pivotX || self.pivotY) {
self.view.layer.anchorPoint = CGPointMake(self.pivotX.floatValue
?: 0.5f, self.pivotY.floatValue ?: 0.5f);
}
2019-07-30 15:20:11 +08:00
}
- (void)blendView:(UIView *)view forPropName:(NSString *)name propValue:(id)prop {
2019-10-12 14:48:19 +08:00
if ([name isEqualToString:@"width"]) {
NSNumber *width = (NSNumber *) prop;
if ([width floatValue] >= 0) {
2019-07-31 14:18:20 +08:00
view.width = [width floatValue];
}
2019-10-12 14:48:19 +08:00
} else if ([name isEqualToString:@"height"]) {
NSNumber *height = (NSNumber *) prop;
if ([height floatValue] >= 0) {
2019-07-31 14:18:20 +08:00
view.height = [height floatValue];
}
2019-10-12 14:48:19 +08:00
} else if ([name isEqualToString:@"x"]) {
view.x = [(NSNumber *) prop floatValue];
} else if ([name isEqualToString:@"y"]) {
view.y = [(NSNumber *) prop floatValue];
2019-12-02 19:09:20 +08:00
} else if ([name isEqualToString:@"backgroundColor"]) {
2019-07-30 15:20:11 +08:00
view.backgroundColor = DoricColor(prop);
2019-11-29 20:02:20 +08:00
} else if ([name isEqualToString:@"alpha"]) {
view.alpha = [prop floatValue];
2019-10-12 14:48:19 +08:00
} else if ([name isEqualToString:@"layoutConfig"]) {
2019-11-15 14:57:41 +08:00
if (self.superNode && [prop isKindOfClass:[NSDictionary class]]) {
[self.superNode blendSubNode:self layoutConfig:prop];
2019-11-28 21:04:27 +08:00
} else {
[self blendLayoutConfig:prop];
2019-07-30 15:20:11 +08:00
}
2019-10-12 14:48:19 +08:00
} else if ([name isEqualToString:@"onClick"]) {
self.callbackIds[@"onClick"] = prop;
2019-07-31 19:22:00 +08:00
view.userInteractionEnabled = YES;
UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onClick:)];
[view addGestureRecognizer:tapGestureRecognizer];
2019-10-12 14:48:19 +08:00
} else if ([name isEqualToString:@"border"]) {
NSDictionary *dic = prop;
CGFloat width = [(NSNumber *) dic[@"width"] floatValue];
UIColor *color = DoricColor((NSNumber *) dic[@"color"]);
view.layer.borderWidth = width;
view.layer.borderColor = color.CGColor;
2019-10-12 14:48:19 +08:00
} else if ([name isEqualToString:@"corners"]) {
if ([prop isKindOfClass:NSNumber.class]) {
view.layer.cornerRadius = [(NSNumber *) prop floatValue];
} else if ([prop isKindOfClass:NSDictionary.class]) {
2019-08-02 20:24:05 +08:00
NSDictionary *dic = prop;
CGFloat leftTop = [(NSNumber *) dic[@"leftTop"] floatValue];
CGFloat rightTop = [(NSNumber *) dic[@"rightTop"] floatValue];
CGFloat rightBottom = [(NSNumber *) dic[@"rightBottom"] floatValue];
CGFloat leftBottom = [(NSNumber *) dic[@"leftBottom"] floatValue];
2019-10-12 14:48:19 +08:00
if (ABS(leftTop - rightTop) > CGFLOAT_MIN
|| ABS(leftTop - rightBottom) > CGFLOAT_MIN
|| ABS(leftTop - leftBottom) > CGFLOAT_MIN) {
2019-08-02 20:24:05 +08:00
view.layer.cornerRadius = 0;
dispatch_async(dispatch_get_main_queue(), ^{
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
CGPathRef path = DoricCreateRoundedRectPath(self.view.bounds, leftTop, rightTop, rightBottom, leftBottom);
shapeLayer.path = path;
CGPathRelease(path);
view.layer.mask = shapeLayer;
});
2019-08-02 20:24:05 +08:00
} else {
view.layer.cornerRadius = leftTop;
view.layer.mask = nil;
2019-08-02 20:24:05 +08:00
}
}
2019-10-12 14:48:19 +08:00
} else if ([name isEqualToString:@"shadow"]) {
NSDictionary *dic = prop;
CGFloat opacity = [(NSNumber *) dic[@"opacity"] floatValue];
if (opacity > CGFLOAT_MIN) {
view.clipsToBounds = NO;
UIColor *color = DoricColor((NSNumber *) dic[@"color"]);
view.layer.shadowColor = color.CGColor;
view.layer.shadowRadius = [(NSNumber *) dic[@"radius"] floatValue];
view.layer.shadowOffset = CGSizeMake([(NSNumber *) dic[@"offsetX"] floatValue], [(NSNumber *) dic[@"offsetY"] floatValue]);
view.layer.shadowOpacity = (float) opacity;
} else {
view.clipsToBounds = YES;
}
2019-11-29 19:17:02 +08:00
} else if ([name isEqualToString:@"translationX"]) {
self.translationX = prop;
} else if ([name isEqualToString:@"translationY"]) {
self.translationY = prop;
} else if ([name isEqualToString:@"scaleX"]) {
self.scaleX = prop;
} else if ([name isEqualToString:@"scaleY"]) {
self.scaleY = prop;
} else if ([name isEqualToString:@"pivotX"]) {
self.pivotX = prop;
} else if ([name isEqualToString:@"pivotY"]) {
self.pivotY = prop;
} else if ([name isEqualToString:@"rotation"]) {
self.rotation = prop;
} else {
2019-07-30 21:05:27 +08:00
DoricLog(@"Blend View error for View Type :%@, prop is %@", self.class, name);
2019-07-30 15:20:11 +08:00
}
}
2019-07-31 19:22:00 +08:00
- (void)onClick:(UIView *)view {
[self callJSResponse:self.callbackIds[@"onClick"], nil];
2019-07-31 14:18:20 +08:00
}
2019-07-30 21:05:27 +08:00
- (NSArray<NSString *> *)idList {
NSMutableArray *ret = [[NSMutableArray alloc] init];
DoricViewNode *node = self;
do {
[ret addObject:node.viewId];
2019-11-15 14:57:41 +08:00
node = node.superNode;
2019-11-25 11:53:31 +08:00
} while (node);
2019-10-12 14:48:19 +08:00
2019-07-31 19:22:00 +08:00
return [[ret reverseObjectEnumerator] allObjects];
2019-07-30 21:05:27 +08:00
}
2019-11-15 19:30:07 +08:00
- (DoricAsyncResult *)callJSResponse:(NSString *)funcId, ... {
2019-07-30 21:05:27 +08:00
NSMutableArray *array = [[NSMutableArray alloc] init];
[array addObject:self.idList];
[array addObject:funcId];
va_list args;
va_start(args, funcId);
id arg;
while ((arg = va_arg(args, id)) != nil) {
[array addObject:arg];
}
2019-11-15 19:30:07 +08:00
DoricAsyncResult *ret = [self.doricContext callEntity:DORIC_ENTITY_RESPONSE withArgumentsArray:array];
2019-07-30 21:05:27 +08:00
va_end(args);
2019-11-15 19:30:07 +08:00
return ret;
2019-07-30 21:05:27 +08:00
}
2019-11-15 19:30:07 +08:00
+ (__kindof DoricViewNode *)create:(DoricContext *)context withType:(NSString *)type {
2019-07-30 21:05:27 +08:00
DoricRegistry *registry = context.driver.registry;
2019-10-12 14:48:19 +08:00
Class clz = [registry acquireViewNode:type];
2019-11-16 13:23:11 +08:00
DoricViewNode *viewNode = [(DoricViewNode *) [clz alloc] initWithContext:context];
viewNode.type = type;
return viewNode;
2019-07-31 14:18:20 +08:00
}
2019-08-06 20:06:34 +08:00
- (void)requestLayout {
2019-11-15 14:57:41 +08:00
[self.superNode requestLayout];
2019-08-06 20:06:34 +08:00
}
2019-11-18 16:33:23 +08:00
- (NSNumber *)getWidth {
return @(self.view.width);
}
- (NSNumber *)getHeight {
return @(self.view.height);
}
2019-11-28 21:04:27 +08:00
- (void)blendLayoutConfig:(NSDictionary *)params {
[params[@"widthSpec"] also:^(NSNumber *it) {
if (it) {
self.layoutConfig.widthSpec = (DoricLayoutSpec) [it integerValue];
}
}];
[params[@"heightSpec"] also:^(NSNumber *it) {
if (it) {
self.layoutConfig.heightSpec = (DoricLayoutSpec) [it integerValue];
}
}];
NSDictionary *margin = params[@"margin"];
if (margin) {
self.layoutConfig.margin = DoricMarginMake(
[(NSNumber *) margin[@"left"] floatValue],
[(NSNumber *) margin[@"top"] floatValue],
[(NSNumber *) margin[@"right"] floatValue],
[(NSNumber *) margin[@"bottom"] floatValue]);
}
NSNumber *alignment = params[@"alignment"];
if (alignment) {
self.layoutConfig.alignment = (DoricGravity) [alignment integerValue];
}
NSNumber *weight = params[@"weight"];
if (weight) {
self.layoutConfig.weight = (DoricGravity) [weight integerValue];
}
}
2019-12-02 18:07:03 +08:00
- (NSDictionary *)transformation {
NSMutableDictionary *dictionary = [NSMutableDictionary new];
if (self.translationX) {
dictionary[@"translationX"] = self.translationX;
}
if (self.translationY) {
dictionary[@"translationY"] = self.translationY;
}
if (self.scaleX) {
dictionary[@"scaleX"] = self.scaleX;
}
if (self.scaleY) {
dictionary[@"scaleY"] = self.scaleY;
}
if (self.rotation) {
dictionary[@"rotation"] = self.rotation;
}
return dictionary;
}
2019-11-30 18:30:46 +08:00
- (void)doAnimation:(id)params withPromise:(DoricPromise *)promise {
CAAnimation *animation = [self parseAnimation:params];
2019-12-02 18:07:03 +08:00
AnimationCallback *originDelegate = animation.delegate;
2019-12-02 11:07:45 +08:00
AnimationCallback *animationCallback = [[AnimationCallback new] also:^(AnimationCallback *it) {
2019-12-02 18:07:03 +08:00
it.startBlock = ^(AnimationCallback *callback) {
if (originDelegate) {
originDelegate.startBlock(callback);
}
[self transformProperties];
};
it.endBlock = ^(AnimationCallback *callback) {
if (originDelegate) {
originDelegate.endBlock(callback);
}
[self transformProperties];
[promise resolve:self.transformation];
2019-12-02 11:07:45 +08:00
};
}];
animation.delegate = animationCallback;
2019-12-02 15:04:03 +08:00
if (params[@"delay"]) {
animation.beginTime = CACurrentMediaTime() + [params[@"delay"] floatValue] / 1000;
}
2019-11-30 18:30:46 +08:00
[self.view.layer addAnimation:animation forKey:nil];
}
- (CFTimeInterval)computeDurationOfAnimations:(NSArray<CAAnimation *> *)animations {
__block CFTimeInterval interval = 0;
[animations forEach:^(CAAnimation *obj) {
interval = MAX(interval, obj.beginTime + obj.duration * (1 + obj.repeatCount));
}];
2019-12-02 18:07:03 +08:00
return interval;
}
2019-11-30 18:30:46 +08:00
- (CAAnimation *)parseAnimation:(id)params {
2019-12-02 15:04:03 +08:00
if (params[@"animations"]) {
NSArray *anims = params[@"animations"];
2019-11-30 18:30:46 +08:00
CAAnimationGroup *animationGroup = [CAAnimationGroup animation];
NSMutableArray *animations = [NSMutableArray new];
[anims forEach:^(id obj) {
[animations addObject:[self parseAnimation:obj]];
}];
animationGroup.duration = [self computeDurationOfAnimations:animations];
2019-11-30 18:30:46 +08:00
animationGroup.animations = animations;
2019-12-02 18:07:03 +08:00
animationGroup.delegate = [[AnimationCallback new] also:^(AnimationCallback *it) {
it.startBlock = ^(AnimationCallback *callback) {
[[animations map:^id(CABasicAnimation *obj) {
return obj.delegate;
}] forEach:^(AnimationCallback *obj) {
if (obj.startBlock) {
obj.startBlock(obj);
}
}];
};
it.endBlock = ^(AnimationCallback *callback) {
[[animations map:^id(CABasicAnimation *obj) {
return obj.delegate;
}] forEach:^(AnimationCallback *obj) {
if (obj.endBlock) {
obj.endBlock(obj);
}
}];
};
}];
2019-12-02 15:04:03 +08:00
if (params[@"delay"]) {
animationGroup.beginTime = [params[@"delay"] floatValue] / 1000;
}
2019-11-30 18:30:46 +08:00
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]) {
2019-12-02 18:07:03 +08:00
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"]];
2019-11-30 18:30:46 +08:00
} else if ([@"translationY" isEqualToString:key]) {
2019-12-02 18:07:03 +08:00
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"]];
2019-11-30 18:30:46 +08:00
}
2019-12-02 18:07:03 +08:00
2019-11-30 18:30:46 +08:00
}];
animation.fromValue = [NSValue valueWithCGPoint:from];
animation.toValue = [NSValue valueWithCGPoint:to];
[self setAnimation:animation params:params];
2019-11-30 18:30:46 +08:00
return animation;
} else {
CAAnimationGroup *animationGroup = [CAAnimationGroup animation];
2019-12-02 18:07:03 +08:00
NSMutableArray <CABasicAnimation *> *animations = [NSMutableArray new];
2019-11-30 18:30:46 +08:00
[changeables forEach:^(NSDictionary *obj) {
2019-12-02 18:07:03 +08:00
CABasicAnimation *animation = [self parseChangeable:obj fillMode:params[@"fillMode"]];
[animations addObject:animation];
2019-11-30 18:30:46 +08:00
}];
animationGroup.animations = animations;
2019-12-02 18:07:03 +08:00
animationGroup.delegate = [[AnimationCallback new] also:^(AnimationCallback *it) {
it.startBlock = ^(AnimationCallback *callback) {
[[animations map:^id(CABasicAnimation *obj) {
return obj.delegate;
}] forEach:^(AnimationCallback *obj) {
if (obj.startBlock) {
obj.startBlock(obj);
}
}];
};
it.endBlock = ^(AnimationCallback *callback) {
[[animations map:^id(CABasicAnimation *obj) {
return obj.delegate;
}] forEach:^(AnimationCallback *obj) {
if (obj.endBlock) {
obj.endBlock(obj);
}
}];
};
}];
[self setAnimation:animationGroup params:params];
2019-11-30 18:30:46 +08:00
return animationGroup;
}
}
return nil;
}
2019-11-30 18:30:46 +08:00
- (void)setAnimation:(CAAnimation *)animation params:(NSDictionary *)params {
if (params[@"repeatCount"]) {
NSInteger repeatCount = [params[@"repeatCount"] integerValue];
if (repeatCount < 0) {
repeatCount = NSNotFound;
}
animation.repeatCount = repeatCount;
}
if (params[@"repeatMode"]) {
NSInteger repeatMode = [params[@"repeatMode"] integerValue];
animation.autoreverses = repeatMode == 2;
}
2019-11-30 18:30:46 +08:00
if (params[@"delay"]) {
animation.beginTime = [params[@"delay"] floatValue] / 1000;
2019-11-30 18:30:46 +08:00
}
animation.duration = [params[@"duration"] floatValue] / 1000;
2019-11-30 18:30:46 +08:00
}
2019-12-02 18:07:03 +08:00
- (void)setFillMode:(CAAnimation *)animation
key:(NSString *)key
startValue:(NSNumber *)startValue
endValue:(NSNumber *)endValue
fillMode:(NSNumber *)fillMode {
NSUInteger fillModeInt = fillMode.unsignedIntegerValue;
if ((fillModeInt & 2) == 2) {
[self setAnimatedValue:key value:startValue];
}
AnimationCallback *callback = [AnimationCallback new];
AnimationCallback *originCallback = animation.delegate;
__weak typeof(self) _self = self;
callback.startBlock = ^(AnimationCallback *callback) {
__strong typeof(_self) self = _self;
callback.dictionary[key] = [self getAnimatedValue:key];
if (originCallback) {
originCallback.startBlock(callback);
}
};
callback.endBlock = ^(AnimationCallback *callback) {
__strong typeof(_self) self = _self;
if ((fillModeInt & 1) == 1) {
[self setAnimatedValue:key value:endValue];
}
if (originCallback) {
originCallback.endBlock(callback);
}
};
animation.delegate = callback;
}
- (NSNumber *)getAnimatedValue:(NSString *)key {
if ([@"translationX" isEqualToString:key]) {
return self.translationX;
}
if ([@"translationY" isEqualToString:key]) {
return self.translationY;
}
if ([@"scaleX" isEqualToString:key]) {
return self.scaleX;
}
if ([@"scaleY" isEqualToString:key]) {
return self.scaleY;
}
if ([@"rotation" isEqualToString:key]) {
return self.rotation;
}
return nil;
}
- (void)setAnimatedValue:(NSString *)key value:(NSNumber *)value {
if ([@"translationX" isEqualToString:key]) {
self.translationX = value;
} else if ([@"translationY" isEqualToString:key]) {
self.translationY = value;
} else if ([@"scaleX" isEqualToString:key]) {
self.scaleX = value;
} else if ([@"scaleY" isEqualToString:key]) {
self.scaleY = value;
} else if ([@"rotation" isEqualToString:key]) {
self.rotation = value;
}
}
- (CABasicAnimation *)parseChangeable:(NSDictionary *)params fillMode:(NSNumber *)fillMode {
2019-11-30 18:30:46 +08:00
NSString *key = params[@"key"];
CABasicAnimation *animation = [CABasicAnimation animation];
if ([@"scaleX" isEqualToString:key]) {
animation.keyPath = @"transform.scale.x";
animation.fromValue = params[@"fromValue"];
animation.toValue = params[@"toValue"];
} else if ([@"scaleY" isEqualToString:key]) {
animation.keyPath = @"transform.scale.y";
animation.fromValue = params[@"fromValue"];
animation.toValue = params[@"toValue"];
} else if ([@"rotation" isEqualToString:key]) {
animation.keyPath = @"transform.rotation.z";
animation.fromValue = @([params[@"fromValue"] floatValue] * M_PI);
animation.toValue = @([params[@"toValue"] floatValue] * M_PI);
2019-12-02 19:09:20 +08:00
} else if ([@"backgroundColor" isEqualToString:key]) {
2019-11-30 18:30:46 +08:00
animation.keyPath = @"backgroundColor";
animation.fromValue = params[@"fromValue"];
animation.toValue = params[@"toValue"];
}
2019-12-02 18:07:03 +08:00
[self setFillMode:animation
key:key
startValue:params[@"fromValue"]
endValue:params[@"toValue"]
fillMode:fillMode];
2019-11-30 18:30:46 +08:00
return animation;
}
2019-12-02 15:04:03 +08:00
- (CAMediaTimingFillMode)translateToFillMode:(NSNumber *)fillMode {
switch ([fillMode integerValue]) {
case 1:
return kCAFillModeForwards;
case 2:
return kCAFillModeBackwards;
case 3:
return kCAFillModeBoth;
default:
return kCAFillModeRemoved;
}
}
2019-07-30 15:20:11 +08:00
@end