在现代iOS应用开发中,优秀的UI动画不仅能提升用户体验,还能让应用更加生动和吸引人。本文将深入探讨iOS动画开发的核心技术,从基础的UIView动画到高级的Core Animation框架,为开发者提供全面的动画开发指南。
动画系统架构概览
动画架构管理器
@interface AnimationArchitecture : NSObject
@property (nonatomic, strong) NSMutableDictionary *animationManagers;
@property (nonatomic, strong) NSMutableDictionary *performanceMetrics;
@property (nonatomic, assign) BOOL isMonitoring;
@property (nonatomic, strong) NSTimer *monitoringTimer;
+ (instancetype)sharedArchitecture;
// 架构初始化
- (void)initializeArchitecture;
- (void)configureAnimationEnvironment;
- (void)setupPerformanceMonitoring;
// 动画管理器注册
- (void)registerAnimationManager:(id)manager forType:(NSString *)type;
- (id)getAnimationManagerForType:(NSString *)type;
- (void)unregisterAnimationManagerForType:(NSString *)type;
// 性能监控
- (void)startMonitoring;
- (void)stopMonitoring;
- (void)recordAnimationPerformance:(NSString *)animationType duration:(NSTimeInterval)duration frameRate:(CGFloat)frameRate;
- (NSDictionary *)getPerformanceReport;
// 动画优化
- (void)optimizeAnimationPerformance;
- (NSArray *)getOptimizationSuggestions;
- (void)applyOptimizationSettings;
@end
@implementation AnimationArchitecture
+ (instancetype)sharedArchitecture {
static AnimationArchitecture *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
- (instancetype)init {
self = [super init];
if (self) {
self.animationManagers = [NSMutableDictionary dictionary];
self.performanceMetrics = [NSMutableDictionary dictionary];
self.isMonitoring = NO;
}
return self;
}
- (void)initializeArchitecture {
NSLog(@"=== 初始化动画架构 ===");
// 配置动画环境
[self configureAnimationEnvironment];
// 设置性能监控
[self setupPerformanceMonitoring];
NSLog(@"动画架构初始化完成");
}
- (void)configureAnimationEnvironment {
NSLog(@"配置动画环境...");
// 设置全局动画参数
[CATransaction setAnimationDuration:0.3];
[CATransaction setAnimationTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
// 启用硬件加速
[[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationNone];
NSLog(@"动画环境配置完成");
}
- (void)setupPerformanceMonitoring {
NSLog(@"设置性能监控...");
// 初始化性能指标字典
self.performanceMetrics[@"frameRates"] = [NSMutableArray array];
self.performanceMetrics[@"animationDurations"] = [NSMutableArray array];
self.performanceMetrics[@"memoryUsage"] = [NSMutableArray array];
NSLog(@"性能监控设置完成");
}
- (void)registerAnimationManager:(id)manager forType:(NSString *)type {
NSLog(@"注册动画管理器: %@", type);
self.animationManagers[type] = manager;
}
- (id)getAnimationManagerForType:(NSString *)type {
return self.animationManagers[type];
}
- (void)unregisterAnimationManagerForType:(NSString *)type {
NSLog(@"注销动画管理器: %@", type);
[self.animationManagers removeObjectForKey:type];
}
- (void)startMonitoring {
if (self.isMonitoring) {
return;
}
NSLog(@"开始性能监控...");
self.isMonitoring = YES;
// 启动监控定时器
self.monitoringTimer = [NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:@selector(collectPerformanceMetrics)
userInfo:nil
repeats:YES];
}
- (void)stopMonitoring {
if (!self.isMonitoring) {
return;
}
NSLog(@"停止性能监控...");
self.isMonitoring = NO;
[self.monitoringTimer invalidate];
self.monitoringTimer = nil;
}
- (void)collectPerformanceMetrics {
// 收集当前帧率
CGFloat currentFrameRate = [self getCurrentFrameRate];
NSMutableArray *frameRates = self.performanceMetrics[@"frameRates"];
[frameRates addObject:@(currentFrameRate)];
// 收集内存使用情况
NSInteger memoryUsage = [self getCurrentMemoryUsage];
NSMutableArray *memoryUsages = self.performanceMetrics[@"memoryUsage"];
[memoryUsages addObject:@(memoryUsage)];
// 保持数据量在合理范围内
if (frameRates.count > 100) {
[frameRates removeObjectAtIndex:0];
}
if (memoryUsages.count > 100) {
[memoryUsages removeObjectAtIndex:0];
}
}
- (CGFloat)getCurrentFrameRate {
// 简化的帧率计算,实际应用中需要更精确的实现
return 60.0; // 假设60fps
}
- (NSInteger)getCurrentMemoryUsage {
// 获取当前内存使用情况
struct mach_task_basic_info info;
mach_msg_type_number_t size = MACH_TASK_BASIC_INFO_COUNT;
kern_return_t kerr = task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t)&info, &size);
if (kerr == KERN_SUCCESS) {
return info.resident_size;
}
return 0;
}
- (void)recordAnimationPerformance:(NSString *)animationType duration:(NSTimeInterval)duration frameRate:(CGFloat)frameRate {
NSLog(@"记录动画性能: %@ - 时长:%.3f秒, 帧率:%.1ffps", animationType, duration, frameRate);
NSMutableDictionary *animationMetrics = self.performanceMetrics[animationType];
if (!animationMetrics) {
animationMetrics = [NSMutableDictionary dictionary];
animationMetrics[@"durations"] = [NSMutableArray array];
animationMetrics[@"frameRates"] = [NSMutableArray array];
self.performanceMetrics[animationType] = animationMetrics;
}
[animationMetrics[@"durations"] addObject:@(duration)];
[animationMetrics[@"frameRates"] addObject:@(frameRate)];
}
- (NSDictionary *)getPerformanceReport {
NSMutableDictionary *report = [NSMutableDictionary dictionary];
for (NSString *animationType in self.performanceMetrics) {
if ([animationType isEqualToString:@"frameRates"] || [animationType isEqualToString:@"animationDurations"] || [animationType isEqualToString:@"memoryUsage"]) {
continue;
}
NSDictionary *metrics = self.performanceMetrics[animationType];
NSArray *durations = metrics[@"durations"];
NSArray *frameRates = metrics[@"frameRates"];
if (durations.count > 0) {
double totalDuration = 0;
double totalFrameRate = 0;
for (NSNumber *duration in durations) {
totalDuration += [duration doubleValue];
}
for (NSNumber *frameRate in frameRates) {
totalFrameRate += [frameRate doubleValue];
}
report[animationType] = @{
@"averageDuration": @(totalDuration / durations.count),
@"averageFrameRate": @(totalFrameRate / frameRates.count),
@"totalAnimations": @(durations.count)
};
}
}
return report;
}
- (void)optimizeAnimationPerformance {
NSLog(@"优化动画性能...");
// 分析性能报告
NSDictionary *report = [self getPerformanceReport];
for (NSString *animationType in report) {
NSDictionary *metrics = report[animationType];
double averageFrameRate = [metrics[@"averageFrameRate"] doubleValue];
if (averageFrameRate < 30.0) {
NSLog(@"动画类型 %@ 帧率过低: %.1ffps,需要优化", animationType, averageFrameRate);
// 应用优化策略
}
}
NSLog(@"动画性能优化完成");
}
- (NSArray *)getOptimizationSuggestions {
NSMutableArray *suggestions = [NSMutableArray array];
NSDictionary *report = [self getPerformanceReport];
for (NSString *animationType in report) {
NSDictionary *metrics = report[animationType];
double averageFrameRate = [metrics[@"averageFrameRate"] doubleValue];
double averageDuration = [metrics[@"averageDuration"] doubleValue];
if (averageFrameRate < 30.0) {
[suggestions addObject:[NSString stringWithFormat:@"%@ 动画帧率过低,建议减少动画复杂度或使用硬件加速", animationType]];
}
if (averageDuration > 1.0) {
[suggestions addObject:[NSString stringWithFormat:@"%@ 动画时长过长,建议缩短动画时间或分解为多个短动画", animationType]];
}
}
return suggestions;
}
- (void)applyOptimizationSettings {
NSLog(@"应用优化设置...");
// 启用图层光栅化
[CATransaction begin];
[CATransaction setDisableActions:YES];
// 设置全局动画优化参数
[CATransaction setAnimationDuration:0.25]; // 缩短默认动画时长
[CATransaction commit];
NSLog(@"优化设置应用完成");
}
- (void)dealloc {
[self stopMonitoring];
}
@end
Core Animation深度解析
Core Animation管理器
@interface CoreAnimationManager : NSObject
@property (nonatomic, weak) AnimationArchitecture *architecture;
@property (nonatomic, strong) NSMutableDictionary *activeAnimations;
@property (nonatomic, strong) NSMutableDictionary *animationGroups;
@property (nonatomic, assign) NSInteger animationCounter;
+ (instancetype)sharedManager;
// 基础动画
- (CABasicAnimation *)createBasicAnimationWithKeyPath:(NSString *)keyPath
fromValue:(id)fromValue
toValue:(id)toValue
duration:(CFTimeInterval)duration;
// 关键帧动画
- (CAKeyframeAnimation *)createKeyframeAnimationWithKeyPath:(NSString *)keyPath
values:(NSArray *)values
keyTimes:(NSArray *)keyTimes
duration:(CFTimeInterval)duration;
// 动画组
- (CAAnimationGroup *)createAnimationGroupWithAnimations:(NSArray *)animations
duration:(CFTimeInterval)duration;
// 转场动画
- (CATransition *)createTransitionWithType:(NSString *)type
subtype:(NSString *)subtype
duration:(CFTimeInterval)duration;
// 弹簧动画
- (CASpringAnimation *)createSpringAnimationWithKeyPath:(NSString *)keyPath
fromValue:(id)fromValue
toValue:(id)toValue
damping:(CGFloat)damping
stiffness:(CGFloat)stiffness
mass:(CGFloat)mass;
// 动画执行
- (void)addAnimation:(CAAnimation *)animation
toLayer:(CALayer *)layer
forKey:(NSString *)key
completion:(void(^)(BOOL finished))completion;
// 动画控制
- (void)pauseAnimationForLayer:(CALayer *)layer key:(NSString *)key;
- (void)resumeAnimationForLayer:(CALayer *)layer key:(NSString *)key;
- (void)removeAnimationForLayer:(CALayer *)layer key:(NSString *)key;
- (void)removeAllAnimationsForLayer:(CALayer *)layer;
// 动画查询
- (BOOL)isAnimatingLayer:(CALayer *)layer;
- (NSArray *)getAnimationKeysForLayer:(CALayer *)layer;
- (CAAnimation *)getAnimationForLayer:(CALayer *)layer key:(NSString *)key;
@end
@implementation CoreAnimationManager
+ (instancetype)sharedManager {
static CoreAnimationManager *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
- (instancetype)init {
self = [super init];
if (self) {
self.architecture = [AnimationArchitecture sharedArchitecture];
self.activeAnimations = [NSMutableDictionary dictionary];
self.animationGroups = [NSMutableDictionary dictionary];
self.animationCounter = 0;
// 注册到架构管理器
[self.architecture registerAnimationManager:self forType:@"CoreAnimation"];
}
return self;
}
- (CABasicAnimation *)createBasicAnimationWithKeyPath:(NSString *)keyPath
fromValue:(id)fromValue
toValue:(id)toValue
duration:(CFTimeInterval)duration {
NSLog(@"创建基础动画: %@, 时长: %.3f秒", keyPath, duration);
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:keyPath];
animation.fromValue = fromValue;
animation.toValue = toValue;
animation.duration = duration;
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
animation.fillMode = kCAFillModeForwards;
animation.removedOnCompletion = NO;
return animation;
}
- (CAKeyframeAnimation *)createKeyframeAnimationWithKeyPath:(NSString *)keyPath
values:(NSArray *)values
keyTimes:(NSArray *)keyTimes
duration:(CFTimeInterval)duration {
NSLog(@"创建关键帧动画: %@, 关键帧数: %lu, 时长: %.3f秒", keyPath, (unsigned long)values.count, duration);
CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:keyPath];
animation.values = values;
animation.keyTimes = keyTimes;
animation.duration = duration;
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
animation.fillMode = kCAFillModeForwards;
animation.removedOnCompletion = NO;
return animation;
}
- (CAAnimationGroup *)createAnimationGroupWithAnimations:(NSArray *)animations
duration:(CFTimeInterval)duration {
NSLog(@"创建动画组: %lu个动画, 时长: %.3f秒", (unsigned long)animations.count, duration);
CAAnimationGroup *group = [CAAnimationGroup animation];
group.animations = animations;
group.duration = duration;
group.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
group.fillMode = kCAFillModeForwards;
group.removedOnCompletion = NO;
return group;
}
- (CATransition *)createTransitionWithType:(NSString *)type
subtype:(NSString *)subtype
duration:(CFTimeInterval)duration {
NSLog(@"创建转场动画: %@-%@, 时长: %.3f秒", type, subtype, duration);
CATransition *transition = [CATransition animation];
transition.type = type;
transition.subtype = subtype;
transition.duration = duration;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
return transition;
}
- (CASpringAnimation *)createSpringAnimationWithKeyPath:(NSString *)keyPath
fromValue:(id)fromValue
toValue:(id)toValue
damping:(CGFloat)damping
stiffness:(CGFloat)stiffness
mass:(CGFloat)mass {
NSLog(@"创建弹簧动画: %@, 阻尼: %.2f, 刚度: %.2f, 质量: %.2f", keyPath, damping, stiffness, mass);
CASpringAnimation *animation = [CASpringAnimation animationWithKeyPath:keyPath];
animation.fromValue = fromValue;
animation.toValue = toValue;
animation.damping = damping;
animation.stiffness = stiffness;
animation.mass = mass;
animation.duration = animation.settlingDuration;
animation.fillMode = kCAFillModeForwards;
animation.removedOnCompletion = NO;
return animation;
}
- (void)addAnimation:(CAAnimation *)animation
toLayer:(CALayer *)layer
forKey:(NSString *)key
completion:(void(^)(BOOL finished))completion {
NSString *animationId = [self generateAnimationId];
NSDate *startTime = [NSDate date];
NSLog(@"添加动画到图层: %@, 键: %@", animationId, key);
// 设置动画代理
animation.delegate = self;
// 记录动画信息
[self recordAnimationStart:animationId layer:layer animation:animation key:key completion:completion];
// 添加动画到图层
[layer addAnimation:animation forKey:key];
}
- (void)pauseAnimationForLayer:(CALayer *)layer key:(NSString *)key {
NSLog(@"暂停图层动画: %@", key);
CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil];
layer.speed = 0.0;
layer.timeOffset = pausedTime;
}
- (void)resumeAnimationForLayer:(CALayer *)layer key:(NSString *)key {
NSLog(@"恢复图层动画: %@", key);
CFTimeInterval pausedTime = [layer timeOffset];
layer.speed = 1.0;
layer.timeOffset = 0.0;
layer.beginTime = 0.0;
CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime;
layer.beginTime = timeSincePause;
}
- (void)removeAnimationForLayer:(CALayer *)layer key:(NSString *)key {
NSLog(@"移除图层动画: %@", key);
[layer removeAnimationForKey:key];
// 清理动画记录
NSArray *keysToRemove = [NSArray array];
for (NSString *animationId in self.activeAnimations) {
NSDictionary *animationInfo = self.activeAnimations[animationId];
if (animationInfo[@"layer"] == layer && [animationInfo[@"key"] isEqualToString:key]) {
keysToRemove = [keysToRemove arrayByAddingObject:animationId];
}
}
for (NSString *animationId in keysToRemove) {
[self.activeAnimations removeObjectForKey:animationId];
}
}
- (void)removeAllAnimationsForLayer:(CALayer *)layer {
NSLog(@"移除图层所有动画");
[layer removeAllAnimations];
// 清理相关的动画记录
NSArray *keysToRemove = [NSArray array];
for (NSString *animationId in self.activeAnimations) {
NSDictionary *animationInfo = self.activeAnimations[animationId];
if (animationInfo[@"layer"] == layer) {
keysToRemove = [keysToRemove arrayByAddingObject:animationId];
}
}
for (NSString *key in keysToRemove) {
[self.activeAnimations removeObjectForKey:key];
}
}
- (BOOL)isAnimatingLayer:(CALayer *)layer {
return layer.animationKeys.count > 0;
}
- (NSArray *)getAnimationKeysForLayer:(CALayer *)layer {
return layer.animationKeys;
}
- (CAAnimation *)getAnimationForLayer:(CALayer *)layer key:(NSString *)key {
return [layer animationForKey:key];
}
#pragma mark - CAAnimationDelegate
- (void)animationDidStart:(CAAnimation *)anim {
NSLog(@"Core Animation开始");
}
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
NSLog(@"Core Animation结束: %@", flag ? @"完成" : @"中断");
// 查找对应的动画记录
NSString *animationIdToRemove = nil;
void(^completion)(BOOL) = nil;
for (NSString *animationId in self.activeAnimations) {
NSDictionary *animationInfo = self.activeAnimations[animationId];
if (animationInfo[@"animation"] == anim) {
animationIdToRemove = animationId;
completion = animationInfo[@"completion"];
// 记录性能指标
NSDate *startTime = animationInfo[@"startTime"];
NSTimeInterval actualDuration = [[NSDate date] timeIntervalSinceDate:startTime];
[self.architecture recordAnimationPerformance:@"CoreAnimation"
duration:actualDuration
frameRate:60.0];
break;
}
}
// 清理动画记录
if (animationIdToRemove) {
[self.activeAnimations removeObjectForKey:animationIdToRemove];
}
// 执行完成回调
if (completion) {
completion(flag);
}
}
- (NSString *)generateAnimationId {
self.animationCounter++;
return [NSString stringWithFormat:@"CoreAnim_%ld", (long)self.animationCounter];
}
- (void)recordAnimationStart:(NSString *)animationId
layer:(CALayer *)layer
animation:(CAAnimation *)animation
key:(NSString *)key
completion:(void(^)(BOOL finished))completion {
self.activeAnimations[animationId] = @{
@"layer": layer,
@"animation": animation,
@"key": key ?: @"",
@"startTime": [NSDate date],
@"completion": completion ?: ^(BOOL finished) {},
@"type": @"CoreAnimation"
};
}
@end
高级动画效果管理器
@interface AdvancedAnimationManager : NSObject
@property (nonatomic, weak) AnimationArchitecture *architecture;
@property (nonatomic, strong) CoreAnimationManager *coreAnimationManager;
@property (nonatomic, strong) UIViewAnimationManager *uiViewAnimationManager;
+ (instancetype)sharedManager;
// 复杂动画效果
- (void)createParticleAnimationForLayer:(CALayer *)layer
particleType:(NSString *)particleType
duration:(NSTimeInterval)duration
completion:(void(^)(BOOL finished))completion;
- (void)createMorphingAnimationForLayer:(CALayer *)layer
fromPath:(UIBezierPath *)fromPath
toPath:(UIBezierPath *)toPath
duration:(NSTimeInterval)duration
completion:(void(^)(BOOL finished))completion;
- (void)createRippleAnimationForView:(UIView *)view
startPoint:(CGPoint)startPoint
color:(UIColor *)color
duration:(NSTimeInterval)duration
completion:(void(^)(BOOL finished))completion;
- (void)createShimmerAnimationForView:(UIView *)view
duration:(NSTimeInterval)duration
completion:(void(^)(BOOL finished))completion;
// 3D动画效果
- (void)create3DFlipAnimationForView:(UIView *)view
axis:(NSString *)axis
duration:(NSTimeInterval)duration
completion:(void(^)(BOOL finished))completion;
- (void)create3DCubeTransitionFromView:(UIView *)fromView
toView:(UIView *)toView
direction:(NSString *)direction
duration:(NSTimeInterval)duration
completion:(void(^)(BOOL finished))completion;
// 物理动画效果
- (void)createGravityAnimationForView:(UIView *)view
duration:(NSTimeInterval)duration
completion:(void(^)(BOOL finished))completion;
- (void)createCollisionAnimationForViews:(NSArray *)views
duration:(NSTimeInterval)duration
completion:(void(^)(BOOL finished))completion;
// 动画序列
- (void)createAnimationSequence:(NSArray *)animationBlocks
duration:(NSTimeInterval)totalDuration
completion:(void(^)(BOOL finished))completion;
- (void)createParallelAnimations:(NSArray *)animationBlocks
duration:(NSTimeInterval)duration
completion:(void(^)(BOOL finished))completion;
@end
@implementation AdvancedAnimationManager
+ (instancetype)sharedManager {
static AdvancedAnimationManager *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
- (instancetype)init {
self = [super init];
if (self) {
self.architecture = [AnimationArchitecture sharedArchitecture];
self.coreAnimationManager = [CoreAnimationManager sharedManager];
self.uiViewAnimationManager = [UIViewAnimationManager sharedManager];
// 注册到架构管理器
[self.architecture registerAnimationManager:self forType:@"AdvancedAnimation"];
}
return self;
}
- (void)createParticleAnimationForLayer:(CALayer *)layer
particleType:(NSString *)particleType
duration:(NSTimeInterval)duration
completion:(void(^)(BOOL finished))completion {
NSLog(@"创建粒子动画: %@, 时长: %.3f秒", particleType, duration);
// 创建粒子发射器
CAEmitterLayer *emitterLayer = [CAEmitterLayer layer];
emitterLayer.emitterPosition = CGPointMake(layer.bounds.size.width / 2, layer.bounds.size.height / 2);
emitterLayer.emitterSize = layer.bounds.size;
emitterLayer.emitterShape = kCAEmitterLayerRectangle;
emitterLayer.emitterMode = kCAEmitterLayerOutline;
// 创建粒子单元
CAEmitterCell *cell = [CAEmitterCell emitterCell];
cell.birthRate = 100;
cell.lifetime = duration;
cell.velocity = 50;
cell.velocityRange = 20;
cell.emissionRange = M_PI * 2;
cell.scale = 0.1;
cell.scaleRange = 0.05;
// 根据粒子类型设置不同的效果
if ([particleType isEqualToString:@"fire"]) {
cell.color = [UIColor orangeColor].CGColor;
cell.redRange = 0.5;
cell.greenRange = 0.2;
cell.alphaSpeed = -1.0 / duration;
} else if ([particleType isEqualToString:@"snow"]) {
cell.color = [UIColor whiteColor].CGColor;
cell.velocity = 20;
cell.yAcceleration = 50;
} else if ([particleType isEqualToString:@"sparkle"]) {
cell.color = [UIColor yellowColor].CGColor;
cell.scale = 0.05;
cell.scaleSpeed = 0.1;
cell.alphaSpeed = -2.0 / duration;
}
// 创建粒子图像
UIGraphicsBeginImageContextWithOptions(CGSizeMake(10, 10), NO, 0);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor);
CGContextFillEllipseInRect(context, CGRectMake(0, 0, 10, 10));
UIImage *particleImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
cell.contents = (id)particleImage.CGImage;
emitterLayer.emitterCells = @[cell];
[layer addSublayer:emitterLayer];
// 设置动画结束后的清理
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(duration * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[emitterLayer removeFromSuperlayer];
if (completion) {
completion(YES);
}
});
}
- (void)createMorphingAnimationForLayer:(CALayer *)layer
fromPath:(UIBezierPath *)fromPath
toPath:(UIBezierPath *)toPath
duration:(NSTimeInterval)duration
completion:(void(^)(BOOL finished))completion {
NSLog(@"创建形变动画, 时长: %.3f秒", duration);
if (![layer isKindOfClass:[CAShapeLayer class]]) {
NSLog(@"警告: 形变动画需要CAShapeLayer");
if (completion) completion(NO);
return;
}
CAShapeLayer *shapeLayer = (CAShapeLayer *)layer;
// 创建路径动画
CABasicAnimation *pathAnimation = [self.coreAnimationManager createBasicAnimationWithKeyPath:@"path"
fromValue:(id)fromPath.CGPath
toValue:(id)toPath.CGPath
duration:duration];
[self.coreAnimationManager addAnimation:pathAnimation
toLayer:shapeLayer
forKey:@"morphing"
completion:completion];
}
- (void)createRippleAnimationForView:(UIView *)view
startPoint:(CGPoint)startPoint
color:(UIColor *)color
duration:(NSTimeInterval)duration
completion:(void(^)(BOOL finished))completion {
NSLog(@"创建涟漪动画, 起点: (%.1f, %.1f), 时长: %.3f秒", startPoint.x, startPoint.y, duration);
// 创建涟漪图层
CAShapeLayer *rippleLayer = [CAShapeLayer layer];
rippleLayer.frame = view.bounds;
rippleLayer.fillColor = [UIColor clearColor].CGColor;
rippleLayer.strokeColor = color.CGColor;
rippleLayer.lineWidth = 2.0;
// 创建圆形路径
CGFloat maxRadius = MAX(view.bounds.size.width, view.bounds.size.height);
UIBezierPath *startPath = [UIBezierPath bezierPathWithArcCenter:startPoint radius:0 startAngle:0 endAngle:2*M_PI clockwise:YES];
UIBezierPath *endPath = [UIBezierPath bezierPathWithArcCenter:startPoint radius:maxRadius startAngle:0 endAngle:2*M_PI clockwise:YES];
rippleLayer.path = startPath.CGPath;
[view.layer addSublayer:rippleLayer];
// 创建扩散动画
CABasicAnimation *pathAnimation = [self.coreAnimationManager createBasicAnimationWithKeyPath:@"path"
fromValue:(id)startPath.CGPath
toValue:(id)endPath.CGPath
duration:duration];
// 创建透明度动画
CABasicAnimation *opacityAnimation = [self.coreAnimationManager createBasicAnimationWithKeyPath:@"opacity"
fromValue:@1.0
toValue:@0.0
duration:duration];
// 创建动画组
CAAnimationGroup *group = [self.coreAnimationManager createAnimationGroupWithAnimations:@[pathAnimation, opacityAnimation]
duration:duration];
[self.coreAnimationManager addAnimation:group
toLayer:rippleLayer
forKey:@"ripple"
completion:^(BOOL finished) {
[rippleLayer removeFromSuperlayer];
if (completion) {
completion(finished);
}
}];
}
- (void)createShimmerAnimationForView:(UIView *)view
duration:(NSTimeInterval)duration
completion:(void(^)(BOOL finished))completion {
NSLog(@"创建闪光动画, 时长: %.3f秒", duration);
// 创建渐变图层
CAGradientLayer *gradientLayer = [CAGradientLayer layer];
gradientLayer.frame = view.bounds;
gradientLayer.colors = @[
(id)[UIColor clearColor].CGColor,
(id)[UIColor whiteColor].CGColor,
(id)[UIColor clearColor].CGColor
];
gradientLayer.locations = @[@0.0, @0.5, @1.0];
gradientLayer.startPoint = CGPointMake(0, 0.5);
gradientLayer.endPoint = CGPointMake(1, 0.5);
// 设置遮罩
view.layer.mask = gradientLayer;
// 创建位置动画
CABasicAnimation *animation = [self.coreAnimationManager createBasicAnimationWithKeyPath:@"locations"
fromValue:@[@(-0.5), @0.0, @0.5]
toValue:@[@0.5, @1.0, @1.5]
duration:duration];
animation.repeatCount = INFINITY;
[self.coreAnimationManager addAnimation:animation
toLayer:gradientLayer
forKey:@"shimmer"
completion:completion];
}
- (void)create3DFlipAnimationForView:(UIView *)view
axis:(NSString *)axis
duration:(NSTimeInterval)duration
completion:(void(^)(BOOL finished))completion {
NSLog(@"创建3D翻转动画, 轴: %@, 时长: %.3f秒", axis, duration);
// 设置3D变换
CATransform3D transform = CATransform3DIdentity;
transform.m34 = -1.0 / 1000.0; // 透视效果
if ([axis isEqualToString:@"x"]) {
transform = CATransform3DRotate(transform, M_PI, 1, 0, 0);
} else if ([axis isEqualToString:@"y"]) {
transform = CATransform3DRotate(transform, M_PI, 0, 1, 0);
} else if ([axis isEqualToString:@"z"]) {
transform = CATransform3DRotate(transform, M_PI, 0, 0, 1);
}
// 创建3D变换动画
CABasicAnimation *flipAnimation = [self.coreAnimationManager createBasicAnimationWithKeyPath:@"transform"
fromValue:[NSValue valueWithCATransform3D:CATransform3DIdentity]
toValue:[NSValue valueWithCATransform3D:transform]
duration:duration];
[self.coreAnimationManager addAnimation:flipAnimation
toLayer:view.layer
forKey:@"3dFlip"
completion:completion];
}
- (void)create3DCubeTransitionFromView:(UIView *)fromView
toView:(UIView *)toView
direction:(NSString *)direction
duration:(NSTimeInterval)duration
completion:(void(^)(BOOL finished))completion {
NSLog(@"创建3D立方体转场, 方向: %@, 时长: %.3f秒", direction, duration);
// 创建容器视图
UIView *containerView = fromView.superview;
// 设置3D透视
CATransform3D perspective = CATransform3DIdentity;
perspective.m34 = -1.0 / 1000.0;
containerView.layer.sublayerTransform = perspective;
// 设置初始位置
fromView.layer.anchorPoint = CGPointMake(0.5, 0.5);
toView.layer.anchorPoint = CGPointMake(0.5, 0.5);
// 根据方向设置变换
CATransform3D fromTransform, toTransform;
if ([direction isEqualToString:@"left"]) {
fromTransform = CATransform3DRotate(CATransform3DIdentity, -M_PI_2, 0, 1, 0);
toTransform = CATransform3DRotate(CATransform3DIdentity, M_PI_2, 0, 1, 0);
toView.layer.transform = toTransform;
} else if ([direction isEqualToString:@"right"]) {
fromTransform = CATransform3DRotate(CATransform3DIdentity, M_PI_2, 0, 1, 0);
toTransform = CATransform3DRotate(CATransform3DIdentity, -M_PI_2, 0, 1, 0);
toView.layer.transform = toTransform;
} else if ([direction isEqualToString:@"up"]) {
fromTransform = CATransform3DRotate(CATransform3DIdentity, M_PI_2, 1, 0, 0);
toTransform = CATransform3DRotate(CATransform3DIdentity, -M_PI_2, 1, 0, 0);
toView.layer.transform = toTransform;
} else { // down
fromTransform = CATransform3DRotate(CATransform3DIdentity, -M_PI_2, 1, 0, 0);
toTransform = CATransform3DRotate(CATransform3DIdentity, M_PI_2, 1, 0, 0);
toView.layer.transform = toTransform;
}
[containerView addSubview:toView];
// 执行动画
[self.uiViewAnimationManager animateView:containerView
duration:duration
delay:0
options:UIViewAnimationOptionCurveEaseInOut
animations:^{
fromView.layer.transform = fromTransform;
toView.layer.transform = CATransform3DIdentity;
}
completion:^(BOOL finished) {
[fromView removeFromSuperview];
containerView.layer.sublayerTransform = CATransform3DIdentity;
if (completion) {
completion(finished);
}
}];
}
- (void)createGravityAnimationForView:(UIView *)view
duration:(NSTimeInterval)duration
completion:(void(^)(BOOL finished))completion {
NSLog(@"创建重力动画, 时长: %.3f秒", duration);
// 创建物理动画器
UIDynamicAnimator *animator = [[UIDynamicAnimator alloc] initWithReferenceView:view.superview];
// 创建重力行为
UIGravityBehavior *gravity = [[UIGravityBehavior alloc] initWithItems:@[view]];
gravity.gravityDirection = CGVectorMake(0, 1.0);
// 创建碰撞行为
UICollisionBehavior *collision = [[UICollisionBehavior alloc] initWithItems:@[view]];
collision.translatesReferenceBoundsIntoBoundary = YES;
// 创建动态属性
UIDynamicItemBehavior *itemBehavior = [[UIDynamicItemBehavior alloc] initWithItems:@[view]];
itemBehavior.elasticity = 0.6;
itemBehavior.friction = 0.8;
[animator addBehavior:gravity];
[animator addBehavior:collision];
[animator addBehavior:itemBehavior];
// 设置结束定时器
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(duration * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[animator removeAllBehaviors];
if (completion) {
completion(YES);
}
});
}
- (void)createCollisionAnimationForViews:(NSArray *)views
duration:(NSTimeInterval)duration
completion:(void(^)(BOOL finished))completion {
NSLog(@"创建碰撞动画, 视图数量: %lu, 时长: %.3f秒", (unsigned long)views.count, duration);
if (views.count == 0) {
if (completion) completion(NO);
return;
}
UIView *referenceView = [(UIView *)views.firstObject superview];
UIDynamicAnimator *animator = [[UIDynamicAnimator alloc] initWithReferenceView:referenceView];
// 为每个视图添加随机推力
for (UIView *view in views) {
UIPushBehavior *push = [[UIPushBehavior alloc] initWithItems:@[view] mode:UIPushBehaviorModeInstantaneous];
push.pushDirection = CGVectorMake((arc4random_uniform(200) - 100) / 100.0, (arc4random_uniform(200) - 100) / 100.0);
push.magnitude = 0.5;
[animator addBehavior:push];
}
// 创建碰撞行为
UICollisionBehavior *collision = [[UICollisionBehavior alloc] initWithItems:views];
collision.translatesReferenceBoundsIntoBoundary = YES;
// 创建动态属性
UIDynamicItemBehavior *itemBehavior = [[UIDynamicItemBehavior alloc] initWithItems:views];
itemBehavior.elasticity = 0.8;
itemBehavior.friction = 0.5;
[animator addBehavior:collision];
[animator addBehavior:itemBehavior];
// 设置结束定时器
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(duration * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[animator removeAllBehaviors];
if (completion) {
completion(YES);
}
});
}
- (void)createAnimationSequence:(NSArray *)animationBlocks
duration:(NSTimeInterval)totalDuration
completion:(void(^)(BOOL finished))completion {
NSLog(@"创建动画序列, 动画数量: %lu, 总时长: %.3f秒", (unsigned long)animationBlocks.count, totalDuration);
if (animationBlocks.count == 0) {
if (completion) completion(YES);
return;
}
NSTimeInterval intervalDuration = totalDuration / animationBlocks.count;
__block NSInteger currentIndex = 0;
void (^executeNextAnimation)(void) = ^void(void) {
if (currentIndex >= animationBlocks.count) {
if (completion) completion(YES);
return;
}
void(^animationBlock)(void) = animationBlocks[currentIndex];
currentIndex++;
if (animationBlock) {
animationBlock();
}
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(intervalDuration * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
executeNextAnimation();
});
};
executeNextAnimation();
}
- (void)createParallelAnimations:(NSArray *)animationBlocks
duration:(NSTimeInterval)duration
completion:(void(^)(BOOL finished))completion {
NSLog(@"创建并行动画, 动画数量: %lu, 时长: %.3f秒", (unsigned long)animationBlocks.count, duration);
if (animationBlocks.count == 0) {
if (completion) completion(YES);
return;
}
dispatch_group_t group = dispatch_group_create();
for (void(^animationBlock)(void) in animationBlocks) {
dispatch_group_enter(group);
if (animationBlock) {
animationBlock();
}
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(duration * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
dispatch_group_leave(group);
});
}
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
if (completion) {
completion(YES);
}
});
}
@end
动画性能优化
动画性能优化器
@interface AnimationPerformanceOptimizer : NSObject
@property (nonatomic, weak) AnimationArchitecture *architecture;
@property (nonatomic, strong) NSMutableDictionary *performanceMetrics;
@property (nonatomic, strong) NSMutableArray *frameRateHistory;
@property (nonatomic, strong) CADisplayLink *displayLink;
@property (nonatomic, assign) CFTimeInterval lastFrameTime;
@property (nonatomic, assign) NSInteger frameCount;
@property (nonatomic, assign) BOOL isMonitoring;
+ (instancetype)sharedOptimizer;
// 性能监控
- (void)startPerformanceMonitoring;
- (void)stopPerformanceMonitoring;
- (void)recordFrameTime:(CFTimeInterval)frameTime;
- (CGFloat)getCurrentFrameRate;
- (CGFloat)getAverageFrameRate;
// 性能分析
- (NSDictionary *)analyzeAnimationPerformance;
- (NSArray *)identifyPerformanceBottlenecks;
- (NSDictionary *)generateOptimizationSuggestions;
// 动画优化
- (void)optimizeLayerForAnimation:(CALayer *)layer;
- (void)optimizeViewForAnimation:(UIView *)view;
- (void)enableHardwareAcceleration:(CALayer *)layer;
- (void)optimizeAnimationTiming:(CAAnimation *)animation;
// 内存优化
- (void)optimizeMemoryUsage;
- (void)cleanupUnusedAnimations;
- (void)reduceAnimationComplexity:(CAAnimation *)animation;
// 电池优化
- (void)optimizeForBatteryLife;
- (void)adjustAnimationQualityForPowerState;
- (void)pauseNonEssentialAnimations;
@end
@implementation AnimationPerformanceOptimizer
+ (instancetype)sharedOptimizer {
static AnimationPerformanceOptimizer *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
- (instancetype)init {
self = [super init];
if (self) {
self.architecture = [AnimationArchitecture sharedArchitecture];
self.performanceMetrics = [NSMutableDictionary dictionary];
self.frameRateHistory = [NSMutableArray array];
self.frameCount = 0;
self.isMonitoring = NO;
// 监听电池状态变化
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(batteryStateDidChange:)
name:UIDeviceBatteryStateDidChangeNotification
object:nil];
// 监听内存警告
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(memoryWarningReceived:)
name:UIApplicationDidReceiveMemoryWarningNotification
object:nil];
}
return self;
}
- (void)startPerformanceMonitoring {
if (self.isMonitoring) return;
NSLog(@"开始动画性能监控");
self.isMonitoring = YES;
self.frameCount = 0;
self.lastFrameTime = CACurrentMediaTime();
self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(displayLinkTick:)];
[self.displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
}
- (void)stopPerformanceMonitoring {
if (!self.isMonitoring) return;
NSLog(@"停止动画性能监控");
self.isMonitoring = NO;
[self.displayLink invalidate];
self.displayLink = nil;
}
- (void)displayLinkTick:(CADisplayLink *)displayLink {
CFTimeInterval currentTime = CACurrentMediaTime();
CFTimeInterval deltaTime = currentTime - self.lastFrameTime;
if (deltaTime > 0) {
CGFloat frameRate = 1.0 / deltaTime;
[self recordFrameTime:frameRate];
}
self.lastFrameTime = currentTime;
self.frameCount++;
}
- (void)recordFrameTime:(CFTimeInterval)frameRate {
[self.frameRateHistory addObject:@(frameRate)];
// 保持历史记录在合理范围内
if (self.frameRateHistory.count > 300) { // 保留最近5秒的数据(60fps)
[self.frameRateHistory removeObjectAtIndex:0];
}
// 记录性能指标
self.performanceMetrics[@"currentFrameRate"] = @(frameRate);
self.performanceMetrics[@"frameCount"] = @(self.frameCount);
self.performanceMetrics[@"averageFrameRate"] = @([self getAverageFrameRate]);
}
- (CGFloat)getCurrentFrameRate {
if (self.frameRateHistory.count == 0) return 0.0;
return [self.frameRateHistory.lastObject floatValue];
}
- (CGFloat)getAverageFrameRate {
if (self.frameRateHistory.count == 0) return 0.0;
CGFloat total = 0.0;
for (NSNumber *frameRate in self.frameRateHistory) {
total += [frameRate floatValue];
}
return total / self.frameRateHistory.count;
}
- (NSDictionary *)analyzeAnimationPerformance {
NSLog(@"分析动画性能");
CGFloat currentFPS = [self getCurrentFrameRate];
CGFloat averageFPS = [self getAverageFrameRate];
// 计算性能等级
NSString *performanceLevel;
if (averageFPS >= 55) {
performanceLevel = @"优秀";
} else if (averageFPS >= 45) {
performanceLevel = @"良好";
} else if (averageFPS >= 30) {
performanceLevel = @"一般";
} else {
performanceLevel = @"差";
}
// 计算帧率稳定性
CGFloat frameRateVariance = [self calculateFrameRateVariance];
NSString *stability;
if (frameRateVariance < 5) {
stability = @"稳定";
} else if (frameRateVariance < 10) {
stability = @"较稳定";
} else {
stability = @"不稳定";
}
return @{
@"currentFPS": @(currentFPS),
@"averageFPS": @(averageFPS),
@"performanceLevel": performanceLevel,
@"frameRateVariance": @(frameRateVariance),
@"stability": stability,
@"frameCount": @(self.frameCount),
@"monitoringDuration": @(self.frameRateHistory.count / 60.0)
};
}
- (CGFloat)calculateFrameRateVariance {
if (self.frameRateHistory.count < 2) return 0.0;
CGFloat average = [self getAverageFrameRate];
CGFloat sumOfSquares = 0.0;
for (NSNumber *frameRate in self.frameRateHistory) {
CGFloat diff = [frameRate floatValue] - average;
sumOfSquares += diff * diff;
}
return sqrt(sumOfSquares / self.frameRateHistory.count);
}
- (NSArray *)identifyPerformanceBottlenecks {
NSLog(@"识别性能瓶颈");
NSMutableArray *bottlenecks = [NSMutableArray array];
CGFloat averageFPS = [self getAverageFrameRate];
CGFloat variance = [self calculateFrameRateVariance];
if (averageFPS < 30) {
[bottlenecks addObject:@{
@"type": @"低帧率",
@"severity": @"高",
@"description": @"平均帧率低于30fps,严重影响用户体验",
@"value": @(averageFPS)
}];
}
if (variance > 10) {
[bottlenecks addObject:@{
@"type": @"帧率不稳定",
@"severity": @"中",
@"description": @"帧率波动较大,可能存在性能问题",
@"value": @(variance)
}];
}
// 检查内存使用情况
NSInteger memoryUsage = [self getCurrentMemoryUsage];
if (memoryUsage > 100 * 1024 * 1024) { // 100MB
[bottlenecks addObject:@{
@"type": @"内存使用过高",
@"severity": @"中",
@"description": @"内存使用超过100MB,可能影响性能",
@"value": @(memoryUsage)
}];
}
return bottlenecks;
}
- (NSInteger)getCurrentMemoryUsage {
struct mach_task_basic_info info;
mach_msg_type_number_t size = MACH_TASK_BASIC_INFO_COUNT;
kern_return_t kerr = task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t)&info, &size);
return (kerr == KERN_SUCCESS) ? info.resident_size : 0;
}
- (NSDictionary *)generateOptimizationSuggestions {
NSLog(@"生成优化建议");
NSMutableArray *suggestions = [NSMutableArray array];
NSArray *bottlenecks = [self identifyPerformanceBottlenecks];
for (NSDictionary *bottleneck in bottlenecks) {
NSString *type = bottleneck[@"type"];
if ([type isEqualToString:@"低帧率"]) {
[suggestions addObject:@{
@"category": @"性能优化",
@"suggestion": @"减少动画复杂度,使用硬件加速",
@"priority": @"高",
@"implementation": @"启用shouldRasterize,优化图层结构"
}];
} else if ([type isEqualToString:@"帧率不稳定"]) {
[suggestions addObject:@{
@"category": @"稳定性优化",
@"suggestion": @"优化动画时序,避免主线程阻塞",
@"priority": @"中",
@"implementation": @"使用CADisplayLink同步动画"
}];
} else if ([type isEqualToString:@"内存使用过高"]) {
[suggestions addObject:@{
@"category": @"内存优化",
@"suggestion": @"清理未使用的动画资源",
@"priority": @"中",
@"implementation": @"及时移除完成的动画,释放图层"
}];
}
}
return @{
@"suggestions": suggestions,
@"totalCount": @(suggestions.count),
@"highPriority": @([self countSuggestionsByPriority:suggestions priority:@"高"]),
@"mediumPriority": @([self countSuggestionsByPriority:suggestions priority:@"中"]),
@"lowPriority": @([self countSuggestionsByPriority:suggestions priority:@"低"])
};
}
- (NSInteger)countSuggestionsByPriority:(NSArray *)suggestions priority:(NSString *)priority {
NSInteger count = 0;
for (NSDictionary *suggestion in suggestions) {
if ([suggestion[@"priority"] isEqualToString:priority]) {
count++;
}
}
return count;
}
- (void)optimizeLayerForAnimation:(CALayer *)layer {
NSLog(@"优化图层动画性能");
// 启用硬件加速
[self enableHardwareAcceleration:layer];
// 优化图层属性
layer.drawsAsynchronously = YES;
layer.allowsEdgeAntialiasing = NO;
layer.allowsGroupOpacity = NO;
// 设置合适的光栅化
if (layer.sublayers.count > 3) {
layer.shouldRasterize = YES;
layer.rasterizationScale = [UIScreen mainScreen].scale;
}
}
- (void)optimizeViewForAnimation:(UIView *)view {
NSLog(@"优化视图动画性能");
// 优化视图属性
view.layer.opaque = YES;
view.clipsToBounds = YES;
// 优化子视图
for (UIView *subview in view.subviews) {
[self optimizeViewForAnimation:subview];
}
// 优化图层
[self optimizeLayerForAnimation:view.layer];
}
- (void)enableHardwareAcceleration:(CALayer *)layer {
NSLog(@"启用硬件加速");
// 确保图层在GPU上渲染
layer.drawsAsynchronously = YES;
// 避免触发软件渲染的属性
layer.shadowPath = nil; // 如果有阴影,使用shadowPath
layer.masksToBounds = YES;
// 设置合适的像素格式
if ([layer respondsToSelector:@selector(setContentsFormat:)]) {
layer.contentsFormat = kCAContentsFormatRGBA8Uint;
}
}
- (void)optimizeAnimationTiming:(CAAnimation *)animation {
NSLog(@"优化动画时序");
// 设置合适的时间函数
if (!animation.timingFunction) {
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
}
// 优化动画持续时间
if (animation.duration > 2.0) {
NSLog(@"警告: 动画持续时间过长,可能影响性能");
}
// 设置合适的填充模式
animation.fillMode = kCAFillModeForwards;
animation.removedOnCompletion = NO;
}
- (void)optimizeMemoryUsage {
NSLog(@"优化内存使用");
// 清理未使用的动画
[self cleanupUnusedAnimations];
// 清理性能历史数据
if (self.frameRateHistory.count > 300) {
NSRange range = NSMakeRange(0, self.frameRateHistory.count - 300);
[self.frameRateHistory removeObjectsInRange:range];
}
// 清理性能指标
[self.performanceMetrics removeAllObjects];
}
- (void)cleanupUnusedAnimations {
NSLog(@"清理未使用的动画");
// 通知架构管理器清理动画
[self.architecture cleanupCompletedAnimations];
}
- (void)reduceAnimationComplexity:(CAAnimation *)animation {
NSLog(@"降低动画复杂度");
if ([animation isKindOfClass:[CAKeyframeAnimation class]]) {
CAKeyframeAnimation *keyframeAnim = (CAKeyframeAnimation *)animation;
// 减少关键帧数量
if (keyframeAnim.values.count > 10) {
NSMutableArray *reducedValues = [NSMutableArray array];
NSInteger step = keyframeAnim.values.count / 5; // 保留5个关键帧
for (NSInteger i = 0; i < keyframeAnim.values.count; i += step) {
[reducedValues addObject:keyframeAnim.values[i]];
}
keyframeAnim.values = reducedValues;
}
}
}
- (void)optimizeForBatteryLife {
NSLog(@"优化电池寿命");
UIDeviceBatteryState batteryState = [UIDevice currentDevice].batteryState;
if (batteryState == UIDeviceBatteryStateUnplugged) {
float batteryLevel = [UIDevice currentDevice].batteryLevel;
if (batteryLevel < 0.2) { // 电量低于20%
[self pauseNonEssentialAnimations];
} else if (batteryLevel < 0.5) { // 电量低于50%
[self adjustAnimationQualityForPowerState];
}
}
}
- (void)adjustAnimationQualityForPowerState {
NSLog(@"根据电源状态调整动画质量");
// 降低动画帧率
if (self.displayLink) {
self.displayLink.preferredFramesPerSecond = 30; // 从60fps降到30fps
}
// 通知架构管理器调整动画质量
[self.architecture adjustAnimationQualityForPowerSaving:YES];
}
- (void)pauseNonEssentialAnimations {
NSLog(@"暂停非必要动画");
// 通知架构管理器暂停非必要动画
[self.architecture pauseNonEssentialAnimations];
}
#pragma mark - Notification Handlers
- (void)batteryStateDidChange:(NSNotification *)notification {
NSLog(@"电池状态变化");
[self optimizeForBatteryLife];
}
- (void)memoryWarningReceived:(NSNotification *)notification {
NSLog(@"收到内存警告");
[self optimizeMemoryUsage];
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
[self stopPerformanceMonitoring];
}
@end
动画最佳实践
动画最佳实践管理器
@interface AnimationBestPractices : NSObject
@property (nonatomic, weak) AnimationArchitecture *architecture;
@property (nonatomic, strong) AnimationPerformanceOptimizer *performanceOptimizer;
+ (instancetype)sharedPractices;
// 设计原则
- (NSDictionary *)getAnimationDesignPrinciples;
- (BOOL)validateAnimationDesign:(NSDictionary *)animationConfig;
- (NSArray *)getAnimationGuidelines;
// 性能最佳实践
- (void)applyPerformanceBestPractices:(CALayer *)layer;
- (void)optimizeAnimationChain:(NSArray *)animations;
- (BOOL)shouldUseHardwareAcceleration:(CAAnimation *)animation;
// 用户体验最佳实践
- (NSTimeInterval)getRecommendedDurationForAnimationType:(NSString *)type;
- (CAMediaTimingFunction *)getRecommendedTimingFunctionForTransition:(NSString *)transition;
- (BOOL)isAnimationAccessible:(CAAnimation *)animation;
// 调试和测试
- (void)enableAnimationDebugging;
- (void)disableAnimationDebugging;
- (NSDictionary *)generateAnimationReport;
- (void)validateAnimationPerformance:(CAAnimation *)animation;
// 常见问题解决
- (NSArray *)getCommonAnimationIssues;
- (NSDictionary *)getSolutionForIssue:(NSString *)issue;
- (void)preventCommonMistakes:(CAAnimation *)animation;
@end
@implementation AnimationBestPractices
+ (instancetype)sharedPractices {
static AnimationBestPractices *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
- (instancetype)init {
self = [super init];
if (self) {
self.architecture = [AnimationArchitecture sharedArchitecture];
self.performanceOptimizer = [AnimationPerformanceOptimizer sharedOptimizer];
}
return self;
}
- (NSDictionary *)getAnimationDesignPrinciples {
return @{
@"性能原则": @{
@"description": @"动画应该流畅且高效",
@"guidelines": @[
@"保持60fps的帧率",
@"避免在主线程执行复杂计算",
@"使用硬件加速的属性",
@"合理使用图层光栅化"
]
},
@"用户体验原则": @{
@"description": @"动画应该自然且有意义",
@"guidelines": @[
@"动画时长应该合适(通常0.2-0.5秒)",
@"使用合适的缓动函数",
@"提供视觉反馈",
@"考虑无障碍访问"
]
},
@"一致性原则": @{
@"description": @"动画风格应该统一",
@"guidelines": @[
@"使用统一的动画时长",
@"保持一致的缓动风格",
@"统一的动画方向和行为",
@"遵循平台设计规范"
]
},
@"目的性原则": @{
@"description": @"每个动画都应该有明确的目的",
@"guidelines": @[
@"引导用户注意力",
@"提供状态反馈",
@"增强交互体验",
@"避免无意义的装饰性动画"
]
}
};
}
- (BOOL)validateAnimationDesign:(NSDictionary *)animationConfig {
NSLog(@"验证动画设计");
BOOL isValid = YES;
NSMutableArray *issues = [NSMutableArray array];
// 检查动画时长
NSNumber *duration = animationConfig[@"duration"];
if (duration && ([duration floatValue] < 0.1 || [duration floatValue] > 2.0)) {
[issues addObject:@"动画时长不合适,建议0.1-2.0秒"];
isValid = NO;
}
// 检查动画类型
NSString *type = animationConfig[@"type"];
NSArray *supportedTypes = @[@"basic", @"keyframe", @"group", @"transition", @"spring"];
if (type && ![supportedTypes containsObject:type]) {
[issues addObject:@"不支持的动画类型"];
isValid = NO;
}
// 检查性能影响
NSString *keyPath = animationConfig[@"keyPath"];
NSArray *performanceOptimizedPaths = @[@"opacity", @"transform", @"position"];
if (keyPath && ![performanceOptimizedPaths containsObject:keyPath]) {
[issues addObject:@"动画属性可能影响性能,建议使用opacity、transform或position"];
}
if (issues.count > 0) {
NSLog(@"动画设计验证问题: %@", issues);
}
return isValid;
}
- (NSArray *)getAnimationGuidelines {
return @[
@{
@"category": @"性能指南",
@"items": @[
@"优先使用transform和opacity属性",
@"避免动画frame、bounds、center属性",
@"使用CALayer而不是UIView进行复杂动画",
@"合理设置shouldRasterize属性"
]
},
@{
@"category": @"时序指南",
@"items": @[
@"微交互动画: 0.1-0.2秒",
@"页面转场动画: 0.3-0.5秒",
@"复杂动画序列: 0.5-1.0秒",
@"避免超过2秒的动画"
]
},
@{
@"category": @"缓动指南",
@"items": @[
@"进入动画使用ease-out",
@"退出动画使用ease-in",
@"状态变化使用ease-in-out",
@"弹性效果使用spring动画"
]
},
@{
@"category": @"无障碍指南",
@"items": @[
@"支持减少动画设置",
@"提供动画的替代反馈",
@"避免闪烁和快速变化",
@"确保动画不影响内容可读性"
]
}
];
}
- (void)applyPerformanceBestPractices:(CALayer *)layer {
NSLog(@"应用性能最佳实践");
// 优化图层属性
layer.opaque = YES;
layer.drawsAsynchronously = YES;
// 避免不必要的混合
layer.allowsGroupOpacity = NO;
layer.allowsEdgeAntialiasing = NO;
// 合理使用光栅化
if (layer.sublayers.count > 2) {
layer.shouldRasterize = YES;
layer.rasterizationScale = [UIScreen mainScreen].scale;
}
// 设置合适的内容格式
if ([layer respondsToSelector:@selector(setContentsFormat:)]) {
layer.contentsFormat = kCAContentsFormatRGBA8Uint;
}
}
- (void)optimizeAnimationChain:(NSArray *)animations {
NSLog(@"优化动画链");
for (CAAnimation *animation in animations) {
// 设置合适的时间函数
if (!animation.timingFunction) {
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
}
// 优化动画属性
animation.fillMode = kCAFillModeForwards;
animation.removedOnCompletion = NO;
// 预防常见错误
[self preventCommonMistakes:animation];
}
}
- (BOOL)shouldUseHardwareAcceleration:(CAAnimation *)animation {
// 检查动画类型和属性
if ([animation isKindOfClass:[CABasicAnimation class]]) {
CABasicAnimation *basicAnim = (CABasicAnimation *)animation;
NSString *keyPath = basicAnim.keyPath;
// 这些属性适合硬件加速
NSArray *acceleratedPaths = @[@"opacity", @"transform", @"position", @"bounds"];
return [acceleratedPaths containsObject:keyPath];
}
return YES; // 默认使用硬件加速
}
- (NSTimeInterval)getRecommendedDurationForAnimationType:(NSString *)type {
NSDictionary *durations = @{
@"fade": @0.25,
@"slide": @0.3,
@"scale": @0.2,
@"rotate": @0.4,
@"bounce": @0.6,
@"spring": @0.8,
@"transition": @0.35,
@"modal": @0.4
};
NSNumber *duration = durations[type];
return duration ? [duration doubleValue] : 0.3; // 默认0.3秒
}
- (CAMediaTimingFunction *)getRecommendedTimingFunctionForTransition:(NSString *)transition {
NSDictionary *timingFunctions = @{
@"enter": [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut],
@"exit": [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn],
@"change": [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut],
@"bounce": [CAMediaTimingFunction functionWithControlPoints:0.68 :-0.55 :0.265 :1.55],
@"smooth": [CAMediaTimingFunction functionWithControlPoints:0.25 :0.1 :0.25 :1.0]
};
CAMediaTimingFunction *timingFunction = timingFunctions[transition];
return timingFunction ?: [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
}
- (BOOL)isAnimationAccessible:(CAAnimation *)animation {
// 检查是否支持减少动画设置
BOOL reduceMotionEnabled = UIAccessibilityIsReduceMotionEnabled();
if (reduceMotionEnabled) {
// 检查动画是否为装饰性
if (animation.duration > 0.5) {
NSLog(@"警告: 用户启用了减少动画,建议缩短动画时长或提供替代方案");
return NO;
}
}
return YES;
}
- (void)enableAnimationDebugging {
NSLog(@"启用动画调试");
// 启用Core Animation调试
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"CALayerDebugEnabled"];
// 启用性能监控
[self.performanceOptimizer startPerformanceMonitoring];
}
- (void)disableAnimationDebugging {
NSLog(@"禁用动画调试");
[[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"CALayerDebugEnabled"];
[self.performanceOptimizer stopPerformanceMonitoring];
}
- (NSDictionary *)generateAnimationReport {
NSLog(@"生成动画报告");
NSDictionary *performanceAnalysis = [self.performanceOptimizer analyzeAnimationPerformance];
NSArray *bottlenecks = [self.performanceOptimizer identifyPerformanceBottlenecks];
NSDictionary *suggestions = [self.performanceOptimizer generateOptimizationSuggestions];
return @{
@"timestamp": [NSDate date],
@"performance": performanceAnalysis,
@"bottlenecks": bottlenecks,
@"suggestions": suggestions,
@"guidelines": [self getAnimationGuidelines],
@"principles": [self getAnimationDesignPrinciples]
};
}
- (void)validateAnimationPerformance:(CAAnimation *)animation {
NSLog(@"验证动画性能");
// 检查动画时长
if (animation.duration > 2.0) {
NSLog(@"警告: 动画时长过长,可能影响用户体验");
}
// 检查是否使用硬件加速
if (![self shouldUseHardwareAcceleration:animation]) {
NSLog(@"建议: 考虑使用硬件加速属性以提高性能");
}
// 检查无障碍访问
if (![self isAnimationAccessible:animation]) {
NSLog(@"警告: 动画可能不符合无障碍访问要求");
}
}
- (NSArray *)getCommonAnimationIssues {
return @[
@{
@"issue": @"动画卡顿",
@"causes": @[@"主线程阻塞", @"复杂的图层结构", @"不当的属性动画"],
@"severity": @"高"
},
@{
@"issue": @"内存泄漏",
@"causes": @[@"动画未正确清理", @"循环引用", @"图层未释放"],
@"severity": @"高"
},
@{
@"issue": @"电池消耗过快",
@"causes": @[@"过多的动画", @"高帧率动画", @"复杂的渲染"],
@"severity": @"中"
},
@{
@"issue": @"动画不流畅",
@"causes": @[@"时间函数不当", @"动画冲突", @"性能瓶颈"],
@"severity": @"中"
},
@{
@"issue": @"无障碍问题",
@"causes": @[@"未考虑减少动画设置", @"缺少替代反馈", @"动画过快"],
@"severity": @"中"
}
];
}
- (NSDictionary *)getSolutionForIssue:(NSString *)issue {
NSDictionary *solutions = @{
@"动画卡顿": @{
@"solutions": @[
@"使用CADisplayLink同步动画",
@"启用硬件加速",
@"优化图层结构",
@"避免在动画中修改frame"
],
@"code_example": @"layer.shouldRasterize = YES;"
},
@"内存泄漏": @{
@"solutions": @[
@"及时移除完成的动画",
@"使用weak引用",
@"正确管理图层生命周期"
],
@"code_example": @"[layer removeAnimationForKey:@\"animationKey\"];"
},
@"电池消耗过快": @{
@"solutions": @[
@"降低动画帧率",
@"减少同时进行的动画",
@"根据电池状态调整动画质量"
],
@"code_example": @"displayLink.preferredFramesPerSecond = 30;"
},
@"动画不流畅": @{
@"solutions": @[
@"使用合适的缓动函数",
@"避免动画冲突",
@"优化动画时序"
],
@"code_example": @"animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];"
},
@"无障碍问题": @{
@"solutions": @[
@"检查减少动画设置",
@"提供替代反馈方案",
@"调整动画时长"
],
@"code_example": @"if (UIAccessibilityIsReduceMotionEnabled()) { /* 提供替代方案 */ }"
}
};
return solutions[issue] ?: @{@"solutions": @[@"未找到解决方案"]};
}
- (void)preventCommonMistakes:(CAAnimation *)animation {
// 确保设置了合适的fillMode
if (!animation.fillMode) {
animation.fillMode = kCAFillModeForwards;
}
// 确保动画不会自动移除
animation.removedOnCompletion = NO;
// 检查动画时长
if (animation.duration <= 0) {
NSLog(@"警告: 动画时长无效,设置为默认值0.3秒");
animation.duration = 0.3;
}
// 设置合适的时间函数
if (!animation.timingFunction) {
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
}
}
@end
综合动画管理系统
综合动画管理器
@interface ComprehensiveAnimationManager : NSObject
@property (nonatomic, strong) AnimationArchitecture *architecture;
@property (nonatomic, strong) UIViewAnimationManager *uiViewAnimationManager;
@property (nonatomic, strong) CoreAnimationManager *coreAnimationManager;
@property (nonatomic, strong) AdvancedAnimationManager *advancedAnimationManager;
@property (nonatomic, strong) AnimationPerformanceOptimizer *performanceOptimizer;
@property (nonatomic, strong) AnimationBestPractices *bestPractices;
+ (instancetype)sharedManager;
// 系统初始化
- (void)initializeAnimationSystem;
- (void)configureOptimalSettings;
- (void)setupPerformanceMonitoring;
// 系统监控
- (void)startSystemMonitoring;
- (void)stopSystemMonitoring;
- (NSDictionary *)getSystemStatus;
// 动画执行
- (void)executeAnimation:(NSDictionary *)animationConfig completion:(void(^)(BOOL finished))completion;
- (void)executeBatchAnimations:(NSArray *)animations completion:(void(^)(BOOL allFinished))completion;
- (void)executeSequentialAnimations:(NSArray *)animations completion:(void(^)(BOOL allFinished))completion;
// 智能动画调度
- (void)scheduleAnimationWithPriority:(NSString *)priority config:(NSDictionary *)config completion:(void(^)(BOOL finished))completion;
- (void)adaptiveAnimationScheduling:(BOOL)enabled;
- (void)balanceAnimationLoad;
// 系统优化
- (void)optimizeSystemPerformance;
- (void)adjustQualityBasedOnConditions;
- (void)cleanupSystemResources;
// 状态查询
- (NSDictionary *)getPerformanceMetrics;
- (NSArray *)getOptimizationRecommendations;
- (NSDictionary *)diagnoseSystemIssues;
@end
@implementation ComprehensiveAnimationManager
+ (instancetype)sharedManager {
static ComprehensiveAnimationManager *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
- (instancetype)init {
self = [super init];
if (self) {
[self initializeAnimationSystem];
}
return self;
}
- (void)initializeAnimationSystem {
NSLog(@"初始化综合动画管理系统");
// 初始化各个管理器
self.architecture = [AnimationArchitecture sharedArchitecture];
self.uiViewAnimationManager = [UIViewAnimationManager sharedManager];
self.coreAnimationManager = [CoreAnimationManager sharedManager];
self.advancedAnimationManager = [AdvancedAnimationManager sharedManager];
self.performanceOptimizer = [AnimationPerformanceOptimizer sharedOptimizer];
self.bestPractices = [AnimationBestPractices sharedPractices];
// 配置最优设置
[self configureOptimalSettings];
// 设置性能监控
[self setupPerformanceMonitoring];
}
- (void)configureOptimalSettings {
NSLog(@"配置最优设置");
// 配置架构设置
[self.architecture configureOptimalSettings];
// 启用自适应调度
[self adaptiveAnimationScheduling:YES];
// 配置性能优化
[self.performanceOptimizer optimizeForBatteryLife];
}
- (void)setupPerformanceMonitoring {
NSLog(@"设置性能监控");
// 启用性能监控
[self.performanceOptimizer startPerformanceMonitoring];
// 启用调试(开发环境)
#ifdef DEBUG
[self.bestPractices enableAnimationDebugging];
#endif
}
- (void)startSystemMonitoring {
NSLog(@"开始系统监控");
[self.performanceOptimizer startPerformanceMonitoring];
[self.architecture startMonitoring];
}
- (void)stopSystemMonitoring {
NSLog(@"停止系统监控");
[self.performanceOptimizer stopPerformanceMonitoring];
[self.architecture stopMonitoring];
}
- (NSDictionary *)getSystemStatus {
NSLog(@"获取系统状态");
NSDictionary *performanceStatus = [self.performanceOptimizer analyzeAnimationPerformance];
NSDictionary *architectureStatus = [self.architecture getSystemStatus];
return @{
@"timestamp": [NSDate date],
@"performance": performanceStatus,
@"architecture": architectureStatus,
@"activeAnimations": @([self.architecture getActiveAnimationCount]),
@"memoryUsage": @([self getCurrentMemoryUsage]),
@"systemHealth": [self evaluateSystemHealth]
};
}
- (NSString *)evaluateSystemHealth {
NSDictionary *performance = [self.performanceOptimizer analyzeAnimationPerformance];
CGFloat averageFPS = [performance[@"averageFPS"] floatValue];
if (averageFPS >= 55) {
return @"优秀";
} else if (averageFPS >= 45) {
return @"良好";
} else if (averageFPS >= 30) {
return @"一般";
} else {
return @"需要优化";
}
}
- (NSInteger)getCurrentMemoryUsage {
struct mach_task_basic_info info;
mach_msg_type_number_t size = MACH_TASK_BASIC_INFO_COUNT;
kern_return_t kerr = task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t)&info, &size);
return (kerr == KERN_SUCCESS) ? info.resident_size : 0;
}
- (void)executeAnimation:(NSDictionary *)animationConfig completion:(void(^)(BOOL finished))completion {
NSLog(@"执行动画: %@", animationConfig[@"type"]);
// 验证动画设计
if (![self.bestPractices validateAnimationDesign:animationConfig]) {
NSLog(@"警告: 动画设计验证失败");
}
NSString *animationType = animationConfig[@"type"];
NSString *engine = animationConfig[@"engine"] ?: @"auto";
// 根据引擎类型执行动画
if ([engine isEqualToString:@"uiview"] || ([engine isEqualToString:@"auto"] && [self shouldUseUIViewAnimation:animationType])) {
[self.uiViewAnimationManager executeAnimation:animationConfig completion:completion];
} else if ([engine isEqualToString:@"coreanimation"] || [engine isEqualToString:@"auto"]) {
[self.coreAnimationManager executeAnimation:animationConfig completion:completion];
} else {
NSLog(@"错误: 不支持的动画引擎: %@", engine);
if (completion) completion(NO);
}
}
- (BOOL)shouldUseUIViewAnimation:(NSString *)animationType {
NSArray *uiViewTypes = @[@"fade", @"slide", @"scale", @"spring"];
return [uiViewTypes containsObject:animationType];
}
- (void)executeBatchAnimations:(NSArray *)animations completion:(void(^)(BOOL allFinished))completion {
NSLog(@"执行批量动画,数量: %lu", (unsigned long)animations.count);
dispatch_group_t group = dispatch_group_create();
__block BOOL allFinished = YES;
for (NSDictionary *animationConfig in animations) {
dispatch_group_enter(group);
[self executeAnimation:animationConfig completion:^(BOOL finished) {
if (!finished) {
allFinished = NO;
}
dispatch_group_leave(group);
}];
}
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"批量动画执行完成,成功: %@", allFinished ? @"是" : @"否");
if (completion) completion(allFinished);
});
}
- (void)executeSequentialAnimations:(NSArray *)animations completion:(void(^)(BOOL allFinished))completion {
NSLog(@"执行顺序动画,数量: %lu", (unsigned long)animations.count);
[self executeSequentialAnimationsRecursive:animations index:0 completion:completion];
}
- (void)executeSequentialAnimationsRecursive:(NSArray *)animations index:(NSInteger)index completion:(void(^)(BOOL allFinished))completion {
if (index >= animations.count) {
NSLog(@"顺序动画执行完成");
if (completion) completion(YES);
return;
}
NSDictionary *animationConfig = animations[index];
[self executeAnimation:animationConfig completion:^(BOOL finished) {
if (finished) {
[self executeSequentialAnimationsRecursive:animations index:index + 1 completion:completion];
} else {
NSLog(@"顺序动画在索引 %ld 处失败", (long)index);
if (completion) completion(NO);
}
}];
}
- (void)scheduleAnimationWithPriority:(NSString *)priority config:(NSDictionary *)config completion:(void(^)(BOOL finished))completion {
NSLog(@"调度优先级动画: %@", priority);
// 根据优先级调整动画配置
NSMutableDictionary *adjustedConfig = [config mutableCopy];
if ([priority isEqualToString:@"high"]) {
// 高优先级动画立即执行
[self executeAnimation:adjustedConfig completion:completion];
} else if ([priority isEqualToString:@"medium"]) {
// 中优先级动画稍微延迟
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self executeAnimation:adjustedConfig completion:completion];
});
} else {
// 低优先级动画在系统空闲时执行
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self executeAnimation:adjustedConfig completion:completion];
});
}
}
- (void)adaptiveAnimationScheduling:(BOOL)enabled {
NSLog(@"自适应动画调度: %@", enabled ? @"启用" : @"禁用");
if (enabled) {
// 根据系统性能自动调整动画质量
[self.architecture enableAdaptiveScheduling];
} else {
[self.architecture disableAdaptiveScheduling];
}
}
- (void)balanceAnimationLoad {
NSLog(@"平衡动画负载");
// 获取当前性能指标
NSDictionary *performance = [self.performanceOptimizer analyzeAnimationPerformance];
CGFloat averageFPS = [performance[@"averageFPS"] floatValue];
if (averageFPS < 45) {
// 性能不佳,减少动画复杂度
[self.architecture reduceAnimationComplexity];
[self.performanceOptimizer adjustAnimationQualityForPowerState];
} else if (averageFPS > 55) {
// 性能良好,可以增加动画质量
[self.architecture increaseAnimationQuality];
}
}
- (void)optimizeSystemPerformance {
NSLog(@"优化系统性能");
// 清理资源
[self cleanupSystemResources];
// 优化内存使用
[self.performanceOptimizer optimizeMemoryUsage];
// 平衡动画负载
[self balanceAnimationLoad];
// 应用最佳实践
[self applySystemBestPractices];
}
- (void)applySystemBestPractices {
NSLog(@"应用系统最佳实践");
// 获取所有活动的图层
NSArray *activeLayers = [self.architecture getActiveLayers];
for (CALayer *layer in activeLayers) {
[self.bestPractices applyPerformanceBestPractices:layer];
}
}
- (void)adjustQualityBasedOnConditions {
NSLog(@"根据条件调整质量");
// 检查电池状态
UIDeviceBatteryState batteryState = [UIDevice currentDevice].batteryState;
float batteryLevel = [UIDevice currentDevice].batteryLevel;
// 检查内存使用
NSInteger memoryUsage = [self getCurrentMemoryUsage];
// 检查性能
CGFloat averageFPS = [[self.performanceOptimizer analyzeAnimationPerformance][@"averageFPS"] floatValue];
// 根据条件调整
if (batteryState == UIDeviceBatteryStateUnplugged && batteryLevel < 0.3) {
[self.performanceOptimizer pauseNonEssentialAnimations];
} else if (memoryUsage > 150 * 1024 * 1024) { // 150MB
[self.performanceOptimizer optimizeMemoryUsage];
} else if (averageFPS < 40) {
[self.performanceOptimizer adjustAnimationQualityForPowerState];
}
}
- (void)cleanupSystemResources {
NSLog(@"清理系统资源");
// 清理完成的动画
[self.architecture cleanupCompletedAnimations];
// 清理未使用的动画
[self.performanceOptimizer cleanupUnusedAnimations];
// 清理缓存
[self.architecture clearCache];
}
- (NSDictionary *)getPerformanceMetrics {
NSLog(@"获取性能指标");
NSDictionary *performanceAnalysis = [self.performanceOptimizer analyzeAnimationPerformance];
NSArray *bottlenecks = [self.performanceOptimizer identifyPerformanceBottlenecks];
return @{
@"timestamp": [NSDate date],
@"frameRate": performanceAnalysis,
@"bottlenecks": bottlenecks,
@"memoryUsage": @([self getCurrentMemoryUsage]),
@"activeAnimations": @([self.architecture getActiveAnimationCount]),
@"systemHealth": [self evaluateSystemHealth]
};
}
- (NSArray *)getOptimizationRecommendations {
NSLog(@"获取优化建议");
NSDictionary *suggestions = [self.performanceOptimizer generateOptimizationSuggestions];
NSArray *guidelines = [self.bestPractices getAnimationGuidelines];
NSMutableArray *recommendations = [NSMutableArray array];
// 添加性能优化建议
NSArray *performanceSuggestions = suggestions[@"suggestions"];
[recommendations addObjectsFromArray:performanceSuggestions];
// 添加最佳实践建议
for (NSDictionary *guideline in guidelines) {
[recommendations addObject:@{
@"category": guideline[@"category"],
@"type": @"最佳实践",
@"items": guideline[@"items"]
}];
}
return recommendations;
}
- (NSDictionary *)diagnoseSystemIssues {
NSLog(@"诊断系统问题");
NSMutableDictionary *diagnosis = [NSMutableDictionary dictionary];
// 性能问题诊断
NSArray *bottlenecks = [self.performanceOptimizer identifyPerformanceBottlenecks];
if (bottlenecks.count > 0) {
diagnosis[@"performanceIssues"] = bottlenecks;
}
// 常见问题诊断
NSArray *commonIssues = [self.bestPractices getCommonAnimationIssues];
NSMutableArray *detectedIssues = [NSMutableArray array];
for (NSDictionary *issue in commonIssues) {
if ([self detectIssue:issue]) {
[detectedIssues addObject:issue];
}
}
if (detectedIssues.count > 0) {
diagnosis[@"commonIssues"] = detectedIssues;
}
// 系统健康状况
diagnosis[@"systemHealth"] = [self evaluateSystemHealth];
diagnosis[@"timestamp"] = [NSDate date];
return diagnosis;
}
- (BOOL)detectIssue:(NSDictionary *)issue {
NSString *issueType = issue[@"issue"];
if ([issueType isEqualToString:@"动画卡顿"]) {
CGFloat averageFPS = [[self.performanceOptimizer analyzeAnimationPerformance][@"averageFPS"] floatValue];
return averageFPS < 45;
} else if ([issueType isEqualToString:@"内存泄漏"]) {
NSInteger memoryUsage = [self getCurrentMemoryUsage];
return memoryUsage > 200 * 1024 * 1024; // 200MB
} else if ([issueType isEqualToString:@"电池消耗过快"]) {
UIDeviceBatteryState batteryState = [UIDevice currentDevice].batteryState;
return batteryState == UIDeviceBatteryStateUnplugged && [UIDevice currentDevice].batteryLevel < 0.2;
}
return NO;
}
@end
动画开发最佳实践总结
核心设计原则
在iOS动画开发中,我们应该遵循以下核心原则:
性能优先原则
- 保持60fps的流畅体验
- 优先使用硬件加速的属性(transform、opacity)
- 合理使用图层光栅化和缓存机制
- 避免在主线程执行复杂的动画计算
用户体验原则
- 动画应该自然且有意义,增强而非干扰用户交互
- 遵循平台设计规范,保持一致的动画风格
- 考虑无障碍访问,支持减少动画设置
- 提供适当的视觉反馈和状态指示
系统可靠性原则
- 正确管理动画生命周期,避免内存泄漏
- 实现优雅的错误处理和降级方案
- 根据设备性能和电池状态自适应调整
- 提供完善的调试和监控机制
开发阶段建议
设计阶段
- 明确动画的目的和用户价值
- 选择合适的动画类型和时长
- 考虑不同设备和系统版本的兼容性
- 设计降级方案和无障碍替代方案
实现阶段
- 使用本文提供的管理器架构
- 优先选择性能最优的动画属性
- 实现完善的错误处理机制
- 添加性能监控和调试支持
测试阶段
- 在不同设备上测试性能表现
- 验证无障碍访问功能
- 测试极端条件下的行为
- 进行内存泄漏和性能分析
维护阶段
- 持续监控动画性能指标
- 根据用户反馈优化体验
- 适配新的iOS版本和设备
- 定期清理和优化动画代码
通过遵循这些原则和建议,结合本文提供的完整动画管理系统,开发者可以创建出既美观又高效的iOS动画效果,为用户提供卓越的交互体验。
UIView动画深度解析
UIView动画管理器
@interface UIViewAnimationManager : NSObject
@property (nonatomic, weak) AnimationArchitecture *architecture;
@property (nonatomic, strong) NSMutableDictionary *activeAnimations;
@property (nonatomic, assign) NSInteger animationCounter;
+ (instancetype)sharedManager;
// 基础动画
- (void)animateView:(UIView *)view
duration:(NSTimeInterval)duration
delay:(NSTimeInterval)delay
options:(UIViewAnimationOptions)options
animations:(void(^)(void))animations
completion:(void(^)(BOOL finished))completion;
// 弹簧动画
- (void)springAnimateView:(UIView *)view
duration:(NSTimeInterval)duration
damping:(CGFloat)damping
velocity:(CGFloat)velocity
options:(UIViewAnimationOptions)options
animations:(void(^)(void))animations
completion:(void(^)(BOOL finished))completion;
// 关键帧动画
- (void)keyframeAnimateView:(UIView *)view
duration:(NSTimeInterval)duration
delay:(NSTimeInterval)delay
options:(UIViewKeyframeAnimationOptions)options
animations:(void(^)(void))animations
completion:(void(^)(BOOL finished))completion;
// 转场动画
- (void)transitionWithView:(UIView *)view
duration:(NSTimeInterval)duration
options:(UIViewAnimationOptions)options
animations:(void(^)(void))animations
completion:(void(^)(BOOL finished))completion;
// 动画控制
- (void)pauseAnimationsForView:(UIView *)view;
- (void)resumeAnimationsForView:(UIView *)view;
- (void)stopAnimationsForView:(UIView *)view;
- (void)stopAllAnimations;
// 动画状态查询
- (BOOL)isAnimatingView:(UIView *)view;
- (NSArray *)getActiveAnimations;
- (NSDictionary *)getAnimationInfo:(NSString *)animationId;
@end
@implementation UIViewAnimationManager
+ (instancetype)sharedManager {
static UIViewAnimationManager *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
- (instancetype)init {
self = [super init];
if (self) {
self.architecture = [AnimationArchitecture sharedArchitecture];
self.activeAnimations = [NSMutableDictionary dictionary];
self.animationCounter = 0;
// 注册到架构管理器
[self.architecture registerAnimationManager:self forType:@"UIViewAnimation"];
}
return self;
}
- (void)animateView:(UIView *)view
duration:(NSTimeInterval)duration
delay:(NSTimeInterval)delay
options:(UIViewAnimationOptions)options
animations:(void(^)(void))animations
completion:(void(^)(BOOL finished))completion {
NSString *animationId = [self generateAnimationId];
NSDate *startTime = [NSDate date];
NSLog(@"开始UIView动画: %@, 时长: %.3f秒", animationId, duration);
// 记录动画信息
[self recordAnimationStart:animationId view:view duration:duration];
[UIView animateWithDuration:duration
delay:delay
options:options
animations:^{
if (animations) {
animations();
}
}
completion:^(BOOL finished) {
NSTimeInterval actualDuration = [[NSDate date] timeIntervalSinceDate:startTime];
// 记录性能指标
[self.architecture recordAnimationPerformance:@"UIViewBasic"
duration:actualDuration
frameRate:60.0];
// 清理动画记录
[self recordAnimationEnd:animationId];
NSLog(@"UIView动画完成: %@, 实际时长: %.3f秒", animationId, actualDuration);
if (completion) {
completion(finished);
}
}];
}
- (void)springAnimateView:(UIView *)view
duration:(NSTimeInterval)duration
damping:(CGFloat)damping
velocity:(CGFloat)velocity
options:(UIViewAnimationOptions)options
animations:(void(^)(void))animations
completion:(void(^)(BOOL finished))completion {
NSString *animationId = [self generateAnimationId];
NSDate *startTime = [NSDate date];
NSLog(@"开始弹簧动画: %@, 时长: %.3f秒, 阻尼: %.2f, 速度: %.2f", animationId, duration, damping, velocity);
// 记录动画信息
[self recordAnimationStart:animationId view:view duration:duration];
[UIView animateWithDuration:duration
delay:0
usingSpringWithDamping:damping
initialSpringVelocity:velocity
options:options
animations:^{
if (animations) {
animations();
}
}
completion:^(BOOL finished) {
NSTimeInterval actualDuration = [[NSDate date] timeIntervalSinceDate:startTime];
// 记录性能指标
[self.architecture recordAnimationPerformance:@"UIViewSpring"
duration:actualDuration
frameRate:60.0];
// 清理动画记录
[self recordAnimationEnd:animationId];
NSLog(@"弹簧动画完成: %@, 实际时长: %.3f秒", animationId, actualDuration);
if (completion) {
completion(finished);
}
}];
}
- (void)keyframeAnimateView:(UIView *)view
duration:(NSTimeInterval)duration
delay:(NSTimeInterval)delay
options:(UIViewKeyframeAnimationOptions)options
animations:(void(^)(void))animations
completion:(void(^)(BOOL finished))completion {
NSString *animationId = [self generateAnimationId];
NSDate *startTime = [NSDate date];
NSLog(@"开始关键帧动画: %@, 时长: %.3f秒", animationId, duration);
// 记录动画信息
[self recordAnimationStart:animationId view:view duration:duration];
[UIView animateKeyframesWithDuration:duration
delay:delay
options:options
animations:^{
if (animations) {
animations();
}
}
completion:^(BOOL finished) {
NSTimeInterval actualDuration = [[NSDate date] timeIntervalSinceDate:startTime];
// 记录性能指标
[self.architecture recordAnimationPerformance:@"UIViewKeyframe"
duration:actualDuration
frameRate:60.0];
// 清理动画记录
[self recordAnimationEnd:animationId];
NSLog(@"关键帧动画完成: %@, 实际时长: %.3f秒", animationId, actualDuration);
if (completion) {
completion(finished);
}
}];
}
- (void)transitionWithView:(UIView *)view
duration:(NSTimeInterval)duration
options:(UIViewAnimationOptions)options
animations:(void(^)(void))animations
completion:(void(^)(BOOL finished))completion {
NSString *animationId = [self generateAnimationId];
NSDate *startTime = [NSDate date];
NSLog(@"开始转场动画: %@, 时长: %.3f秒", animationId, duration);
// 记录动画信息
[self recordAnimationStart:animationId view:view duration:duration];
[UIView transitionWithView:view
duration:duration
options:options
animations:^{
if (animations) {
animations();
}
}
completion:^(BOOL finished) {
NSTimeInterval actualDuration = [[NSDate date] timeIntervalSinceDate:startTime];
// 记录性能指标
[self.architecture recordAnimationPerformance:@"UIViewTransition"
duration:actualDuration
frameRate:60.0];
// 清理动画记录
[self recordAnimationEnd:animationId];
NSLog(@"转场动画完成: %@, 实际时长: %.3f秒", animationId, actualDuration);
if (completion) {
completion(finished);
}
}];
}
- (void)pauseAnimationsForView:(UIView *)view {
NSLog(@"暂停视图动画: %@", view);
CALayer *layer = view.layer;
CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil];
layer.speed = 0.0;
layer.timeOffset = pausedTime;
}
- (void)resumeAnimationsForView:(UIView *)view {
NSLog(@"恢复视图动画: %@", view);
CALayer *layer = view.layer;
CFTimeInterval pausedTime = [layer timeOffset];
layer.speed = 1.0;
layer.timeOffset = 0.0;
layer.beginTime = 0.0;
CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime;
layer.beginTime = timeSincePause;
}
- (void)stopAnimationsForView:(UIView *)view {
NSLog(@"停止视图动画: %@", view);
[view.layer removeAllAnimations];
// 清理相关的动画记录
NSArray *keysToRemove = [NSArray array];
for (NSString *animationId in self.activeAnimations) {
NSDictionary *animationInfo = self.activeAnimations[animationId];
if (animationInfo[@"view"] == view) {
keysToRemove = [keysToRemove arrayByAddingObject:animationId];
}
}
for (NSString *key in keysToRemove) {
[self.activeAnimations removeObjectForKey:key];
}
}
- (void)stopAllAnimations {
NSLog(@"停止所有动画");
for (NSString *animationId in self.activeAnimations) {
NSDictionary *animationInfo = self.activeAnimations[animationId];
UIView *view = animationInfo[@"view"];
if (view) {
[view.layer removeAllAnimations];
}
}
[self.activeAnimations removeAllObjects];
}
- (BOOL)isAnimatingView:(UIView *)view {
return view.layer.animationKeys.count > 0;
}
- (NSArray *)getActiveAnimations {
return [self.activeAnimations allKeys];
}
- (NSDictionary *)getAnimationInfo:(NSString *)animationId {
return self.activeAnimations[animationId];
}
- (NSString *)generateAnimationId {
self.animationCounter++;
return [NSString stringWithFormat:@"UIViewAnim_%ld", (long)self.animationCounter];
}
- (void)recordAnimationStart:(NSString *)animationId view:(UIView *)view duration:(NSTimeInterval)duration {
self.activeAnimations[animationId] = @{
@"view": view,
@"duration": @(duration),
@"startTime": [NSDate date],
@"type": @"UIView"
};
}
- (void)recordAnimationEnd:(NSString *)animationId {
[self.activeAnimations removeObjectForKey:animationId];
}
@end
上一篇 下一篇