[iOS Animation]-CALayer 图层几何学

[iOS Animation]-CALayer 图层几何学

图层几何学

不熟悉几何学的人就不要来这里了 –柏拉图学院入口的签名

在第二章里面,我们介绍了图层背后的图片,和一些控制图层坐标和旋转的属性。在这一章中,我们将要看一看图层内部是如何根据父图层和兄弟图层来控制位置和尺寸的。另外我们也会涉及如何管理图层的几何结构,以及它是如何被自动调整和自动布局影响的。

布局

UIView有三个比较重要的布局属性:frame,bounds和center,CALayer对应地叫做frame,bounds和position。为了能清楚区分,图层用了“position”,视图用了“center”,但是他们都代表同样的值。

frame代表了图层的外部坐标(也就是在父图层上占据的空间),bounds是内部坐标({0, 0}通常是图层的左上角),center和position都代表了相对于父图层anchorPoint所在的位置。anchorPoint的属性将会在后续介绍到,现在把它想成图层的中心点就好了。图3.1显示了这些属性是如何相互依赖的。

图3.1

图3.1 UIView和CALayer的坐标系

视图的frame,bounds和center属性仅仅是存取方法,当操纵视图的frame,实际上是在改变位于视图下方CALayer的frame,不能够独立于图层之外改变视图的frame。

对于视图或者图层来说,frame并不是一个非常清晰的属性,它其实是一个虚拟属性,是根据bounds,position和transform计算而来,所以当其中任何一个值发生改变,frame都会变化。相反,改变frame的值同样会影响到他们当中的值

记住当对图层做变换的时候,比如旋转或者缩放,frame实际上代表了覆盖在图层旋转之后的整个轴对齐的矩形区域,也就是说frame的宽高可能和bounds的宽高不再一致了(图3.2)

图3.2

图3.2 旋转一个视图或者图层之后的frame属性

锚点

之前提到过,视图的center属性和图层的position属性都指定了anchorPoint相对于父图层的位置。图层的anchorPoint通过position来控制它的frame的位置,你可以认为anchorPoint是用来移动图层的把柄

默认来说,anchorPoint位于图层的中点,所以图层的将会以这个点为中心放置。anchorPoint属性并没有被UIView接口暴露出来,这也是视图的position属性被叫做“center”的原因。但是图层的anchorPoint可以被移动,比如你可以把它置于图层frame的左上角,于是图层的内容将会向右下角的position方向移动(图3.3),而不是居中了。

图3.3

图3.3 改变anchorPoint的效果

和第二章提到的contentsRect和contentsCenter属性类似,anchorPoint用单位坐标来描述,也就是图层的相对坐标,图层左上角是{0, 0},右下角是{1, 1},因此默认坐标是{0.5, 0.5}。anchorPoint可以通过指定x和y值小于0或者大于1,使它放置在图层范围之外。

注意在图3.3中,当改变了anchorPoint,position属性保持固定的值并没有发生改变,但是frame却移动了。

那在什么场合需要改变anchorPoint呢?既然我们可以随意改变图层位置,那改变anchorPoint不会造成困惑么?为了举例说明,我们来举一个实用的例子,创建一个模拟闹钟的项目。

钟面和钟表由四张图片组成(图3.4),为了简单说明,我们还是用传统的方式来装载和加载图片,使用四个UIImageView实例(当然你也可以用正常的视图,设置他们图层的contents图片)。

图3.4

图3.4 组成钟面和钟表的四张图片

闹钟的组件通过IB来排列(图3.5),这些图片视图嵌套在一个容器视图之内,并且自动调整和自动布局都被禁用了。这是因为自动调整会影响到视图的frame,而根据图3.2的演示,当视图旋转的时候,frame是会发生改变的,这将会导致一些布局上的失灵。

我们用NSTimer来更新闹钟,使用视图的transform属性来旋转钟表(如果你对这个属性不太熟悉,不要着急,我们将会在第5章“变换”当中详细说明),具体代码见清单3.1

图3.5

图3.5 在Interface Builder中布局闹钟视图

清单3.1 Clock

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
@interface ViewController ()
 
@property (nonatomic, weak) IBOutlet UIImageView *hourHand;
@property (nonatomic, weak) IBOutlet UIImageView *minuteHand;
@property (nonatomic, weak) IBOutlet UIImageView *secondHand;
@property (nonatomic, weak) NSTimer *timer;
 
@end
 
@implementation ViewController
 
– (void)viewDidLoad
{
    [super viewDidLoad];
    //start timer
    self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(tick) userInfo:nil repeats:YES];
                  
    //set initial hand positions
    [self tick];
}
 
– (void)tick
{
    //convert time to hours, minutes and seconds
    NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
    NSUInteger units = NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit;
    NSDateComponents *components = [calendar components:units fromDate:[NSDate date]];
    CGFloat hoursAngle = (components.hour / 12.0) * M_PI * 2.0;
    //calculate hour hand angle //calculate minute hand angle
    CGFloat minsAngle = (components.minute / 60.0) * M_PI * 2.0;
    //calculate second hand angle
    CGFloat secsAngle = (components.second / 60.0) * M_PI * 2.0;
    //rotate hands
    self.hourHand.transform = CGAffineTransformMakeRotation(hoursAngle);
    self.minuteHand.transform = CGAffineTransformMakeRotation(minsAngle);
    self.secondHand.transform = CGAffineTransformMakeRotation(secsAngle);
}
 
@end

运行项目,看起来有点奇怪(图3.6),因为钟表的图片在围绕着中心旋转,这并不是我们期待的一个支点。

图3.6

图3.6 钟面,和不对齐的钟指针

你也许会认为可以在Interface Builder当中调整指针图片的位置来解决,但其实并不能达到目的,因为如果不放在钟面中间的话,同样不能正确的旋转。

也许在图片末尾添加一个透明空间也是个解决方案,但这样会让图片变大,也会消耗更多的内存,这样并不优雅。

更好的方案是使用anchorPoint属性,我们来在-viewDidLoad方法中添加几行代码来给每个钟指针的anchorPoint做一些平移(清单3.2),图3.7显示了正确的结果。

清单3.2

1
2
3
4
5
6
7
8
9
10
11
12
– (void)viewDidLoad
{
    [super viewDidLoad];
    // adjust anchor points
 
    self.secondHand.layer.anchorPoint = CGPointMake(0.5f, 0.9f);
    self.minuteHand.layer.anchorPoint = CGPointMake(0.5f, 0.9f);
    self.hourHand.layer.anchorPoint = CGPointMake(0.5f, 0.9f);
 
 
    // start timer
}

图3.7

图3.7 钟面,和正确对齐的钟指针

转载于:https://my.oschina.net/u/2438875/blog/512726

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/109311.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • mybatis获取map的key_mybatis怎么处理结果集

    mybatis获取map的key_mybatis怎么处理结果集实体类:数据库:CREATETABLE`job_title_info`(`_jobtitleid`varchar(255)DEFAULTNULL,`_shortname`varchar(255)DEFAULTNULL,`_fullname`varchar(255)DEFAULTNULL,`_departmentid`varchar…

  • sdn网络的特点(水环式真空泵的工作原理)

    SDN的工作原理SDN网络架构的三层模型架构主要分为协同应用层,控制层,转发层三层,网络架构本身包括管理平面,控制平面和转发平面,与这三层对应。传统的IP网络具有转发平面,控制平面和管理平面。协同应用层主要是完成用户意图的各种上层应用程序,此类应用程序(APP)成为协同应用程序,典型的协同层包括OSS,Openstack等。控制层是系统的控制中心,负责网络内部交换路径和边界业务路由的生成,并负责处理网络状态变化事件。这里注意sdn架构下,sdn控制器直接提供网络业务服务接口,APP就不需关心内部

  • android activity的跳转动画,实现activity跳转动画的若干种方式

    android activity的跳转动画,实现activity跳转动画的若干种方式第一种:(使用overridePendingTransition方法实现Activity跳转动画)在Activity中代码如下/***点击按钮实现跳转逻辑*/button1.setOnClickListener(newView.OnClickListener(){@OverridepublicvoidonClick(Viewv){/***在调用了startActivity方法之后…

  • 如何在Windows上下载,安装或卸载PyCharm?「建议收藏」

    如何在Windows上下载,安装或卸载PyCharm?「建议收藏」PyCharmisaPythonIDEthatprovideseasinesstodevelopedPythonApplication.PyCharmprovidesalotofusefulfeatureslikesmartcodecompletion,codeinspection,on-the-flyerrorhighlighting,qui…

  • Quadro P5200 – 最强大的移动工作站显卡 专门为了惠普 VR Z 背包电脑而发布

    Quadro P5200 – 最强大的移动工作站显卡 专门为了惠普 VR Z 背包电脑而发布https://www.leiphone.com/news/201708/Z1MCetuoobEaHIqa.html前言在今年的计算机图形技术顶会SIGGRAPH,英伟达并不是在单纯地展示自家的

  • vmware15激活码【2022最新】

    (vmware15激活码)好多小伙伴总是说激活码老是失效,太麻烦,关注/收藏全栈君太难教程,2021永久激活的方法等着你。IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.cn/100143.html1TCF2R91JZ-eyJsaWNlbnNlSWQi…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号