1. - (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx
  2. {
  3. CGFloat width = 10.0f;
  4. //draw a thick red circle
  5. CGContextSetLineWidth(ctx, width);
  6. CGContextSetStrokeColorWithColor(ctx, [UIColor redColor].CGColor);
  7. CGRect rect = CGRectMake(layer.bounds.origin.x+width/2, layer.bounds.origin.y+width/2, layer.bounds.size.width-width, layer.bounds.size.height-width);
  8. CGContextStrokeEllipseInRect(ctx, rect);
  9. }

接上次,修改了一下,呵呵,看着舒服多了

由此可见线宽的扩展方式是同时向两边扩展的。

第三章:Layer Geometry

 

“Let no one unversed in geometry enter here.”
看到作者的信心了吧,你有了吗?

UIView的布局属性有frame,bounds和center,CALayer同样有3个对应frame,bounds和position。如图:

需要注意的是,frame不是一个独立的属性,它是由bounds,position,transform等其他属性计算而来,所以改变frame会影响其他属性,反之改变其他属性也会影响frame。如果我在前面的例子里增加一行改变frame的代码你会看到如下结果

  1. - (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx
  2. {
  3. CGFloat width = 10.0f;
  4. //draw a thick red circle
  5. CGContextSetLineWidth(ctx, width);
  6. CGContextSetStrokeColorWithColor(ctx, [UIColor redColor].CGColor);
  7. CGRect rect = CGRectMake(layer.bounds.origin.x+width/2, layer.bounds.origin.y+width/2, layer.bounds.size.width-width, layer.bounds.size.height-width);
  8. CGContextStrokeEllipseInRect(ctx, rect);
  9. layer.frame = CGRectMake(10.0f, 10.0f, 200.0f, 200.0f);
  10. }

还有需要注意在操作transform时,如旋转时,frame会重新计算,此时frame的宽高不再和bounds比配。如图

下面再说说anchorPoint这个属性,很多人对于使用此属性可能会迷惑,到底是怎么设置的,先看张图

anchorPoint从{0.5, 0.5}变为{0, 0},layer向右下偏移了,下面大家可以用一下做个试验

还是使用上面的例子,在- (void)viewDidLoad的[blueLayerdisplay];前增加

  1. NSLog(@"%@", NSStringFromCGPoint(blueLayer.anchorPoint));
  2. NSLog(@"%@", NSStringFromCGPoint(blueLayer.position));

是为了记录变化前的值,接着在- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx中

增加对anchorPoint的设置,自已可以任意设置看看结果

  1. - (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx
  2. {
  3. CGFloat width = 10.0f;
  4. //draw a thick red circle
  5. CGContextSetLineWidth(ctx, width);
  6. CGContextSetStrokeColorWithColor(ctx, [UIColor redColor].CGColor);
  7. CGRect rect = CGRectMake(layer.bounds.origin.x+width/2, layer.bounds.origin.y+width/2, layer.bounds.size.width-width, layer.bounds.size.height-width);
  8. CGContextStrokeEllipseInRect(ctx, rect);
  9. layer.anchorPoint = CGPointMake(0, 0);
  10. NSLog(@"%@", NSStringFromCGPoint(layer.position));
  11. }

我们可以得出结论,anchorPoint可以简单地看作是设置左上顶点相对于中心position的位置,

计数以左上顶点到position的距离与宽高的比例,X轴方向正为左移负为右移,Y轴方向正为上移负为下移。

下面我们用例子来看看具体的应用,具体代码请查看例子3.1

源码在这里下载:http://www.informit.com/title/9780133440751

 
  1. - (void)viewDidLoad
  2. {
  3. [super viewDidLoad];
  4. //start timer
  5. self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0
  6. target:self
  7. selector:@selector(tick)
  8. userInfo:nil
  9. repeats:YES];
  10. //set initial hand positions
  11. [self tick];
  12. }
  13. - (void)tick
  14. {
  15. //convert time to hours, minutes and seconds
  16. NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
  17. NSUInteger units = NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit;
  18. NSDateComponents *components = [calendar components:units fromDate:[NSDate date]];
  19. //calculate hour hand angle
  20. CGFloat hourAngle = (components.hour / 12.0) * M_PI * 2.0;
  21. //calculate minute hand angle
  22. CGFloat minuteAngle = (components.minute / 60.0) * M_PI * 2.0;
  23. //calculate second hand angle
  24. CGFloat secondAngle = (components.second / 60.0) * M_PI * 2.0;
  25. //rotate hands
  26. self.hourHand.transform = CGAffineTransformMakeRotation(hourAngle);
  27. self.minuteHand.transform = CGAffineTransformMakeRotation(minuteAngle);
  28. self.secondHand.transform = CGAffineTransformMakeRotation(secondAngle);
  29. }

运行看看结果

发现什么了没有?CGAffineTransformMakeRotation以View的center点在旋转

再看例子3.2,修改代码

  1. - (void)viewDidLoad
  2. {
  3. [super viewDidLoad];
  4. //adjust anchor points
  5. self.secondHand.layer.anchorPoint = CGPointMake(0.5f, 0.9f); // 为什么不是1.0f?
  6. self.minuteHand.layer.anchorPoint = CGPointMake(0.5f, 0.9f);
  7. self.hourHand.layer.anchorPoint = CGPointMake(0.5f, 0.9f);
  8. //start timer
  9. self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0
  10. target:self
  11. selector:@selector(tick)
  12. userInfo:nil
  13. repeats:YES];
  14. //set initial hand positions
  15. [self tick];
  16. }

看结果

CGAffineTransformMakeRotation以layer的position点在旋转

相对坐标的转换函数,UIView使用:

- (CGPoint)convertPoint:(CGPoint)point toView:(UIView *)view;

- (CGPoint)convertPoint:(CGPoint)point fromView:(UIView *)view;

- (CGRect)convertRect:(CGRect)rect toView:(UIView *)view;

- (CGRect)convertRect:(CGRect)rect fromView:(UIView *)view;

CALayer使用:

- (CGPoint)convertPoint:(CGPoint)p fromLayer:(CALayer *)l;

- (CGPoint)convertPoint:(CGPoint)p toLayer:(CALayer *)l;

- (CGRect)convertRect:(CGRect)r fromLayer:(CALayer *)l;

- (CGRect)convertRect:(CGRect)r toLayer:(CALayer *)l;

注意:直到OS X 10.8才出现了geometryFlipped属性,该属性可以改变默认图层y坐标的方向。当翻转变换被调用时,使用该属性来调整图层的方向有的时候是必需的。如果父视图使用了翻转变换,它的子视图内容(以及它对应的图层)将经常被颠倒。在这种情况下,设置子图层的geometryFlipped属性为YES是一种修正该问题最简单的方法。在OS X 10.8及以上版本,AppKit负责管理该属性,你不应该更改它。对于iOS app,不推荐使用geometryFlipped属性。

“This is a BOOL value that determines whether the geometry of a layer is vertically flipped with respect to its superlayer. Setting this property to YES for a layer on iOS means that its sublayers will be flipped vertically and will be positioned relative to the bottom of its bounds rather than the top as normal (as will all of their sublayers, and so on, unless they also have YES for their geometryFlipped property).”
注意的是geometryFlipped只对sublayers起作用,只到有sub也设置了YES才恢复,有点负负得正的意思

修改例子3.2代码

  1. - (void)viewDidLoad
  2. {
  3. [super viewDidLoad];
  4. //adjust anchor points
  5. self.view.layer.geometryFlipped = YES;
  6. self.secondHand.layer.anchorPoint = CGPointMake(0.5f, 0.9f);
  7. self.minuteHand.layer.anchorPoint = CGPointMake(0.5f, 0.9f);
  8. self.hourHand.layer.anchorPoint = CGPointMake(0.5f, 0.9f);
  9. //start timer
  10. self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0
  11. target:self
  12. selector:@selector(tick)
  13. userInfo:nil
  14. repeats:YES];
  15. //set initial hand positions
  16. [self tick];
  17. }

自己运行看看,指针反着转了。

再修改看看的geometryFlipped sublayers的作用域,呵呵暂且这么说
首先增加一个view作为secondHand的父view,修改代码

增加

  1. @property (weak, nonatomic) IBOutlet UIView *sView;
  1. - (void)viewDidLoad
  2. {
  3. [super viewDidLoad];
  4. //adjust anchor points
  5. self.view.layer.geometryFlipped = YES;
  6. self.sView.layer.geometryFlipped = YES;
  7. self.secondHand.layer.anchorPoint = CGPointMake(0.5f, 0.9f);
  8. self.minuteHand.layer.anchorPoint = CGPointMake(0.5f, 0.9f);
  9. self.hourHand.layer.anchorPoint = CGPointMake(0.5f, 0.9f);
  10. //start timer
  11. self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0
  12. target:self
  13. selector:@selector(tick)
  14. userInfo:nil
  15. repeats:YES];
  16. //set initial hand positions
  17. [self tick];
  18. }

看结果

秒针正常了

我们以前接触的UIView是2维坐标,但现在CAlayer确实3维坐标,增加了Z轴, zPosition 和 anchorPointZ
看例子3.3,zPosition默认值为0,当设置self.greenView.layer.zPosition大于0时,greenView将遮盖redView

运行结果

例子3.4和3.5是对

  1. /* Returns the farthest descendant of the layer containing point 'p'.
  2. * Siblings are searched in top-to-bottom order. 'p' is defined to be
  3. * in the coordinate space of the receiver's nearest ancestor that
  4. * isn't a CATransformLayer (transform layers don't have a 2D
  5. * coordinate space in which the point could be specified). */
  6. - (CALayer *)hitTest:(CGPoint)p;
  7. /* Returns true if the bounds of the layer contains point 'p'. */
  8. - (BOOL)containsPoint:(CGPoint)p;

两个函数的,自己去看

IOS Core Animation Advanced Techniques的学习笔记(二)的更多相关文章

  1. IOS Core Animation Advanced Techniques的学习笔记(一)

    转载. Book Description Publication Date: August 12, 2013 Core Animation is the technology underlying A ...

  2. IOS Core Animation Advanced Techniques的学习笔记(五)

    第六章:Specialized Layers   类别 用途 CAEmitterLayer 用于实现基于Core Animation粒子发射系统.发射器层对象控制粒子的生成和起源 CAGradient ...

  3. IOS Core Animation Advanced Techniques的学习笔记(四)

    第五章:Transforms   Affine Transforms   CGAffineTransform是二维的     Creating a CGAffineTransform   主要有三种变 ...

  4. IOS Core Animation Advanced Techniques的学习笔记(三)

    第四章:Visual Effects   Rounded Corners 例子4.1 cornerRadius 源码在这里下载:http://www.informit.com/title/978013 ...

  5. iOS Core Animation Advanced Techniques

    Book Descripter Core Animation is the technology underlying Apple's iOS user interface. By unleashin ...

  6. 转 iOS Core Animation 动画 入门学习(一)基础

    iOS Core Animation 动画 入门学习(一)基础 reference:https://developer.apple.com/library/ios/documentation/Coco ...

  7. iOS Core Animation 简明系列教程

    iOS Core Animation 简明系列教程  看到无数的CA教程,都非常的难懂,各种事务各种图层关系看的人头大.自己就想用通俗的语言翻译给大家听,尽可能准确表达,如果哪里有问题,请您指出我会尽 ...

  8. iOS - Core Animation 核心动画

    1.UIView 动画 具体讲解见 iOS - UIView 动画 2.UIImageView 动画 具体讲解见 iOS - UIImageView 动画 3.CADisplayLink 定时器 具体 ...

  9. iOS安全些许经验和学习笔记

    http://bbs.pediy.com/showthread.php?t=209014 标题: [原创]iOS安全些许经验和学习笔记作者: MonkeyKey时间: 2016-03-30,16:32 ...

随机推荐

  1. 一行R代码来实现繁琐的可视化

    ggfortify 有着简单易用的统一的界面来用一行代码来对许多受欢迎的R软件包结果进行二维可视化的一个R工具包.这让许多的统计学家以及数据科学家省去了许多繁琐和重复的过程,不用对结果进行任何处理就能 ...

  2. 【leetcode❤python】 204. Count Primes

    #-*- coding: UTF-8 -*- #Hint1:#数字i,i的倍数一定不是质数,因此去掉i的倍数,例如5,5*1,5*2,5*3,5*4,5*5都不是质数,应该去掉#5*1,5*2,5*3 ...

  3. 用户识别APP项目开发计划书

    用户识别APP项目开发计划书        项目介绍: 用户识别APP,通过在有限时间内引导用户A交互,提取用户的行为特征,然后将APP交给用户X(可能是A也可能是陌生人),在1分钟内引导X交互,判断 ...

  4. Cheatsheet: 2016 12.01 ~ 12.31

    Other Code review in remote teams 5 Signs That Your REST API Isn't RESTful Web Server Side React Sta ...

  5. C++知识库

    C++知识库 秒杀多线程 .

  6. mysql 范式和反范式

    第一范式(1NF)强调的是列的原子性,即列不能够再分成其他几列. 第二范式(2NF) 首先是 2NF,另外包含两部分内容一是表必须有一个主键:二是没有包含在主键中的列必须完全依赖于主键,而不能只依赖于 ...

  7. ElasticSearch5+logstash的logstash-input-jdbc实现mysql数据同步

    在实现的路上遇到了各种坑,再次验证官方文档只能产考不能全信! ElasticSearch安装就不说了上一篇有说! 安装logstash 官方:https://www.elastic.co/guide/ ...

  8. hihoCoder 1427 : What a Simple Research(大㵘研究)

    hihoCoder #1427 : What a Simple Research(大㵘研究) 时间限制:1000ms 单点时限:1000ms 内存限制:256MB Description - 题目描述 ...

  9. 转载分享----一线交付眼中的为何"项目总是迟迟无法交付”

    当初博主在一线交付BOSS系统中承担过TC角色 交付的路途很艰辛,加班到10点多或1点多第二天8点上班,还有通宵的日子 还有无数个问题从开始到关闭的周期,各种催人,各种掐架拉会,各种被甲方嫌弃 看到这 ...

  10. jQuery.eq() 函数

    eq() 函数 获取当前对象中指定索引所对应的的元素 语法 $selector.eq(index)//index为指定索引,值为数字型 返回值 返回值为一个对象 实例说明 代码 <!DOCTYP ...