UI基础 - CGAffineTransform | UIView动画
▶ CGAffineTransform
1 - CGAffineTransform 是一个用于处理形变的类,可以改变控件的平移、缩放、旋转等;它的坐标系统采用的是二维坐标系:向右为 x轴 正方向,向下为 y轴 正方向;它的形变是通过仿射变换矩阵来控制的:其中平移是矩阵相加;旋转与缩放则是矩阵相乘
2 - 为了合并矩阵运算中的加法和乘法,引入了齐次坐标的概念:它提供了用矩阵运算把二维、三维甚至高维空间中的一个点集从一个坐标系变换到另一个坐标系的有效方法!CGAffineTransform 形变就是把二维形变使用一个三维矩阵来表示,其中第三列总是 (0,0,1),形变通过前两列来控制
CGAffineTransformMake(CGFloat a, CGFloat b, CGFloat c, CGFloat d, CGFloat tx, CGFloat ty)
通过变换矩阵左乘向量,将空间中的一个点集从一个坐标系变换到另一个坐标系中,计算方式如下
其中 tx 用来控制在 x轴 方向上的平移;ty 用来控制在 y轴 方向上的平移
a 用来控制在 x轴 方向上的缩放;d 用来控制在 y轴 方向上的缩放
abcd 共同控制旋转
3 - 代码示例:仿射变换的基本使用
1 #import "ViewController.h" 2 @implementation ViewController 3 - (void)viewDidLoad { 4 [super viewDidLoad]; 5 self.view.backgroundColor = [UIColor cyanColor]; 6 self.title = @"CGAffineTransform"; 7 8 // Btn 按钮 9 UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom]; 10 btn.frame = CGRectMake(50, 90, self.view.frame.size.width - 100, 30); 11 [btn setTitle:@"点我变换" forState:UIControlStateNormal]; 12 btn.layer.cornerRadius = 6; 13 [btn setTitle:@"松开我" forState:UIControlStateHighlighted]; 14 btn.backgroundColor = [UIColor redColor]; 15 [btn addTarget:self action:@selector(doTransfrom) forControlEvents: UIControlEventTouchUpInside ]; 16 [self.view addSubview:btn]; 17 18 // 图片 19 UILabel *lab = [[UILabel alloc] init]; 20 lab.frame = CGRectMake(80, 150, self.view.frame.size.width - 160, 220) ; 21 lab.text = @"---我是背景文案---"; 22 lab.textAlignment = NSTextAlignmentCenter; 23 lab.tag = 1000; 24 lab.backgroundColor = [UIColor whiteColor]; 25 [self.view addSubview:lab]; 26 } 27 28 // 旋转 29 - (void)doTransfrom{ 30 UILabel *aView = (UILabel *)[self.view viewWithTag:1000]; 31 32 //------------- 测试一:旋转 ------------- 33 // // 当弧度为正值时,顺时针旋转;反之逆时针旋转 34 // // CGAffineTransformMakeRotation 以初始位置为基准 35 // aView.transform = CGAffineTransformMakeRotation(M_PI / 4); 36 // 37 //// // CGAffineTransformRotate:以一个已经存在的形变为基准 38 //// aView.transform = CGAffineTransformRotate(aView.transform, M_PI_4); 39 // 40 // // CGAffineTransformIdentity:可以在形变之后设置该值以还原到最初状态 41 // // 开启动画:验证在形变后还原到初始状态 42 // [UIView beginAnimations:nil context:nil]; 43 // [UIView setAnimationDuration:1.5]; 44 // aView.transform = CGAffineTransformIdentity; 45 // // aView.transform = CGAffineTransformMake(1, 0, 0, 1, 0, 0);// 原始值 46 // [UIView commitAnimations]; 47 48 //------------- 测试二:缩放 ------------- 49 // // CGAffineTransformMakeScale 50 // // 实现以初始位置为基准,在 x轴 方向上缩放 x 倍,在 y轴 方向上缩放 y 倍 51 // // 当 x 为正值时,会在 x轴 方向上缩放 x 倍。反之,则在缩放的基础上沿着竖直线翻转 52 // // 当 y 为正值时,会在 y轴 方向上缩放 y 倍。反之,则在缩放的基础上沿着水平线翻转 53 // aView.transform = CGAffineTransformMakeScale(-0.8, -0.8); 54 // 55 //// // CGAffineTransformScale 以一个已经存在的形变为基准 56 //// aView.transform = CGAffineTransformScale(aView.transform, 0.9, 0.9); 57 58 //------------- 测试三:平移 ------------- 59 // CGAffineTransformMakeTranslation 60 // 实现以初始位置为基准,在 x 轴方向上平移 x 单位,在 y 轴方向上平移 y 单位 61 aView.transform = CGAffineTransformMakeTranslation(20,-30);// 右上 62 63 // // CGAffineTransformTranslate 以一个已经存在的形变为基准 64 // aView.transform = CGAffineTransformTranslate(aView.transform,20,-30); 65 } 66 @end
▶ UIView动画
1 - iOS 中动画主要分为 UIView动画 和 CALayer动画;UIView动画本质上也是 CALayer动画;UIView动画分为 UIView属性动画 和 UIViewTransition动画
2 - UIView属性动画:其动画属性有 frame、center、bounds、alpha、transform、backgroundColor...
3 - 动画方法
// 如果两个动画发生在同一个 View 中,且前一个动画还未结束而后一个动画就开始进行的情况下 // 该方法会将动画运行的当前状态作为下一个状态的开始状态,这样就避免了动画跳跃的不连贯问题 [UIView setAnimationBeginsFromCurrentState:YES];
动画的实现除了可由动画块实现外,也可以使用 block
4 - UIViewTransition
过渡给 UIView动画块 添加了视觉表现力
// cache 参数告诉系统是否用 Cache 进行动画(与硬件相关),一般填 yes + (void)setAnimationTransition:(UIViewAnimationTransition)transition forView:(UIView *)view cache:(BOOL)cache; + (void)transitionFromView:(UIView *)fromView toView:(UIView *)toView duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options completion:(void (^ __nullable)(BOOL finished))completion; + (void)transitionWithView:(UIView *)view duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options animations:(void (^ __nullable)(void))animations completion:(void (^ __nullable)(BOOL finished))completion;
过渡效果在 UIKit 中封装了 4 种效果
typedef NS_ENUM(NSInteger, UIViewAnimationTransition) { UIViewAnimationTransitionNone, UIViewAnimationTransitionFlipFromLeft, // 从左向右旋转 UIViewAnimationTransitionFlipFromRight, // 从右向左旋转 UIViewAnimationTransitionCurlUp, // 向上翻页 UIViewAnimationTransitionCurlDown, // 向下翻页 };
5 - 代码示例
A. UIView动画块
// - ViewController.m
1 #import "ViewController.h" 2 @interface ViewController () 3 @property(nonatomic,strong)UILabel *animationView; // 要执行的动画 UI 4 @property(assign,nonatomic)CGRect frameDemo; // 记录动画视图 初始frame 5 @end 6 7 @implementation ViewController 8 9 - (void)viewDidLoad { 10 [super viewDidLoad]; 11 12 // 动画 13 self.animationView = [[UILabel alloc] initWithFrame:CGRectMake(20, 50, 100, 40)]; 14 self.animationView.text = @"属性动画"; 15 self.animationView.textAlignment = NSTextAlignmentCenter; 16 self.animationView.textColor = [UIColor blackColor]; 17 self.animationView.backgroundColor = [UIColor redColor]; 18 [self.view addSubview:self.animationView]; 19 self.frameDemo = self.animationView.frame; 20 21 // 动画块:开启动画(beginAnimations)到提交动画(commitAnimations)之间的代码 22 23 // 开启动画--------------------------- 24 [UIView beginAnimations:@"animation01" context:@"看看是啥"]; 25 [UIView setAnimationDelay:1.0]; // 延迟 26 [UIView setAnimationDelegate:self];// 设置代理:可以监控动画的开始和结束 27 28 // 也可以定义一个方法使其成为代理方法 29 // 它会覆盖自身相应的代理方法 30 //[UIView setAnimationDidStopSelector:@selector(animationFinished:)]; 31 32 [UIView setAnimationDuration:3.0]; // 动画时间:1 ~ 2 秒为宜 33 [UIView setAnimationRepeatCount:2];// 重复次数 34 [UIView setAnimationRepeatAutoreverses:YES];// 动画反弹 35 [UIView setAnimationCurve:UIViewAnimationCurveEaseOut];// 过渡曲线 36 37 // 影响动画的属性 38 self.animationView.frame = CGRectMake(120, 350, 100, 40); 39 self.animationView.alpha = 0.1; 40 self.animationView.backgroundColor = [UIColor yellowColor]; 41 self.animationView.backgroundColor = [UIColor greenColor]; 42 self.animationView.transform = CGAffineTransformMakeRotation(M_PI); 43 44 // 提交动画-------------------------------- 45 [UIView commitAnimations]; 46 } 47 48 - (void)animationFinished:(id)sender{ 49 NSLog(@"animation01 DidEnd"); 50 } 51 52 #pragma mark - 代理方法 53 // 开始 54 -(void)animationWillStart:(NSString *)animationID context:(void *)context{ 55 if ([animationID isEqualToString:@"animation01"]) { 56 NSLog(@"animation01 will start--%@",context); 57 } 58 } 59 60 // 结束:finished 参数很重要,我们可以用来判断动画是否是正常结束(正常返回 1,否则返回 0) 61 - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{ 62 63 // UIView动画:如果 frame 发生改变,动画结束后它不会恢复倒初始位置 64 // 恢复原来的 frame 65 self.animationView.frame = self.frameDemo; 66 self.animationView.alpha = 1.0f; 67 } 68 69 @end
过渡曲线有四种方式
1 UIViewAnimationCurveEaseInOut // 淡入淡出效果最为自然,也是默认效果 2 UIViewAnimationCurveEaseIn 3 UIViewAnimationCurveEaseOut 4 UIViewAnimationCurveLinear
B. block动画
// - ViewController.m
1 #import "ViewController.h" 2 @interface ViewController () 3 @property(nonatomic,strong)UILabel *animationView; 4 @property(assign,nonatomic)CGRect frame; 5 @end 6 7 @implementation ViewController 8 9 - (void)viewDidLoad { 10 [super viewDidLoad]; 11 12 // 动画视图 13 self.animationView = [[UILabel alloc] initWithFrame:CGRectMake(100, 120, 40, 200)]; 14 self.animationView.text = @"block动画"; 15 self.animationView.textAlignment = NSTextAlignmentCenter; 16 self.animationView.textColor = [UIColor blackColor]; 17 self.animationView.backgroundColor = [UIColor redColor]; 18 [self.view addSubview:self.animationView]; 19 self.frame = self.animationView.frame; 20 21 //-------------------- UIView动画:缩放 22 // [UIView beginAnimations:nil context:nil]; 23 // [UIView setAnimationDuration:2.0f]; 24 // self.animationView.transform = CGAffineTransformMakeScale(1.2, 1.2); 25 // // catch:第二次翻转时会从内存中取,效率较高 26 // [UIView setAnimationTransition:UIViewAnimationTransitionCurlUp forView:self.animationView cache:YES]; 27 // [UIView commitAnimations]; 28 29 //--------------------------- Block动画 30 // [UIView animateWithDuration:5.0 animations:^{ 31 // [UIView setAnimationRepeatCount:2]; 32 // [UIView setAnimationRepeatAutoreverses:YES]; 33 // self.animationView.frame = CGRectMake(120, 400, 100, 80); 34 // self.animationView.backgroundColor = [UIColor blackColor]; 35 // }]; 36 37 //--------------------------- Block动画:弹簧效果 38 // // usingSpringWithDamping:弹簧力度,值越小越弹动越快 39 // [UIView animateWithDuration:1.0 delay:0 usingSpringWithDamping:0.1f initialSpringVelocity:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ 40 // CGRect rect = self.animationView.frame; 41 // rect.origin.y += 150; 42 // self.animationView.frame = rect; 43 // } completion:^(BOOL finished){ 44 // self.animationView.backgroundColor = [UIColor yellowColor]; 45 // }]; 46 47 48 //--------------------------- Block动画:动画嵌套 49 // // 第一层 50 // [UIView animateWithDuration:2.0 animations:^{ 51 // self.animationView.frame = CGRectMake(120, 400, 80, 80); 52 // self.animationView.backgroundColor = [UIColor blackColor]; 53 // } completion:^(BOOL finished){ 54 // 55 // NSLog(@"%@",finished ? @"YES" : @"NO"); 56 // self.animationView.frame = self.frame; 57 // self.animationView.backgroundColor = [UIColor greenColor]; 58 // 59 // // 第二层 60 // [UIView animateWithDuration:2.0 animations:^{ 61 // self.animationView.transform =CGAffineTransformRotate(self.animationView.transform, M_PI); 62 // } completion:^(BOOL finished) { 63 // [UIView animateWithDuration:2.0 animations:^{ 64 // self.animationView.alpha = 0.3; 65 // }]; 66 // }]; 67 // }]; 68 69 //--------------------------- 动画嵌套 70 // 第一层 71 [UIView transitionWithView:self.animationView duration:2.0 options:UIViewAnimationOptionTransitionFlipFromLeft animations:^{ 72 // y 下移 100 73 CGRect rect = self.animationView.frame; 74 rect.origin.y += 100; 75 self.animationView.frame = rect; 76 } completion:^(BOOL finished) { 77 78 // 第二层:UIView动画块 79 [UIView beginAnimations:nil context:nil]; 80 CGRect rect = self.animationView.frame; 81 [UIView setAnimationDuration:2.0]; 82 // y 上移 100 83 rect.origin.y -= 100; 84 self.animationView.frame = rect; 85 [UIView commitAnimations]; 86 }]; 87 } 88 89 @end
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)