CALayer常用属性整理(二)

接着捋~

锚点(anchorPoint)

锚点也需要使用单位坐标,默认是(0.5,0.5),也就是中心点。当把锚点值设置为(0,0)时锚点将位于图层左上角,(1,1)时为右下角,以此类推。

关于锚点的使用书中给了一个时钟的例子,而在开发中我唯一使用到锚点的场景是在制作抽奖的转盘时,为了给奖品的图片做旋转,需要更改图片的锚点来处理(其实和时钟例子的用法几乎一样)。大概就是下面图片中的效果。

anchorPoint.png

至于转盘的实现方式和代码,等把该整理的都整理完,如果还想再写点东西的话再附上一篇抽奖转盘的实现吧= =。

不同坐标系之间的转换方法

就是这几个方法:
- (CGPoint)convertPoint:(CGPoint)point fromLayer:(CALayer *)layer;
- (CGPoint)convertPoint:(CGPoint)point toLayer:(CALayer *)layer;
- (CGRect)convertRect:(CGRect)rect fromLayer:(CALayer *)layer;
- (CGRect)convertRect:(CGRect)rect toLayer:(CALayer *)layer;

拿第一个方法为例,意思按我自己的理解大概就是将点(point)从图层(layer)中的值转换到当前图层,并返回转换后的值。第二个方法:将点(point)从他所在的图层转移到指定图层(layer),并返回转以后的值。

或者可以看下面的一个例子。

UIView *outView = [[UIView alloc] initWithFrame:CGRectMake(30, 30, 300, 300)];
outView.backgroundColor = [UIColor whiteColor];
[self.view addSubview:outView];

CALayer *innerLayer = [CALayer layer];
innerLayer.backgroundColor = [UIColor redColor].CGColor;
innerLayer.frame = CGRectMake(0, 0, 50, 50);
innerLayer.position = outView.layer.position;
[outView.layer addSublayer:innerLayer];

首先定义了一个外层的outView,然后在outView.layer上添加了一个新的图层叫innerLayer,并且让innerLayer在outView.layer上居中显示。我们期望这段代码执行后看到的效果应该是这样的。

期望的效果图.png

但是实际上运行起来会是这样的。

实际的效果图.png

看到这样的效果,老司机肯定会暗骂一声“凑,xxx忘写了”。然后萌新就会有点懵“麻辣鸡,这是什么鬼,说好的居中呢”

至于为什么会出现上图中的效果,是因为白色View中position的值是以它的父视图(也就是灰色的view)来计算的,在本例中这个值是(180,210)。也就是说白色view的position的值是在父视图坐标系中计算出来的。那么这个时候直接把这个值赋给红色layer(innerLayer)的position来达到居中的目的肯定是做不到的。如果我没解释清楚的话直接看position属性(或者UIView的center属性,效果是一样的)的官方解释可能会更清晰。

执行“innerLayer.position = outView.layer.position;”这句代码在本例中等同于“innerLayer.position = CGPointMake(180, 210);”。因为innerLayer的布局是依赖它的父图层(也就是outView.layer)坐标系,而在outView的坐标系中,中心点显然不是(180,210)这个点(明显是(150,150)的啊),所以,导致innerLayer跑偏了。

这个问题就是因为坐标系使用混乱导致的。下面我们将innerLayer的代码这么写:

CALayer *innerLayer = [CALayer layer];
innerLayer.backgroundColor = [UIColor redColor].CGColor;
innerLayer.frame = CGRectMake(0, 0, 50, 50);
CGPoint innerCenter = [self.view.layer convertPoint:outView.layer.position toLayer:outView.layer];
innerLayer.position = innerCenter;
[outView.layer addSublayer:innerLayer];

与之前的代码相比,新加入了一句代码“CGPoint innerCenter = [self.view.layer convertPoint:outView.layer.position toLayer:outView.layer];”。这句代码用来把outView.layer.position的值从他的父视图坐标系转换到outView.layer的坐标系中。innerLayer就可以正常显示了。

zPosition

描述了图层在z轴上的位置,可以用来改变图层显示顺序,注意仅仅是显示顺序。

zPosition默认是0,数值越高它的显示优先级也越高,但是不能改变响应优先级

geometryFlipped

geometryFlipped决定了一个图层的坐标是否相对于父图层垂直翻转,默认情况下是NO,也就是从左上角开始绘制,当把值改为YES的时候这个图层和他的子图层将会被垂直翻转,也就是从左下角开始绘制。

hitTest方法

在说hitTest方法之前要先说CALayer的另一个方法:

- (BOOL)containsPoint:(CGPoint)p;

在CALayer属性整理(一)里面开头就提到过CALayer不处理交互,但是它仍提供了一些方法来帮助我们处理交互。上面的方法接受一个在本图层坐标系下的CGPoint,注意是本图层坐标系!如果这个点在该图层的frame范围内返回YES,反之返回NO。

书上有一个这样的例子:首先界面是这样的,一个view上加了个layer就不贴代码了

containsPoint的例子.png

然后在vc里面重写一下touchesBegan方法

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
  //获取self.view坐标系中的触摸点
  CGPoint point = [[touches anyObject] locationInView:self.view];
  //把获取到的点从self.view.layer中转换到self.aView.layer的坐标系中。
  point = [self.aView.layer convertPoint:point fromLayer:self.view.layer];
  //判断self.aView.layer是否包含这个点
  if ([self.aView.layer containsPoint:point]) {
      //继续把点从self.aView.layer中转移到self.blueLayer的坐标系
      point = [self.blueLayer convertPoint:point fromLayer:self.aView.layer];
    
      if ([self.blueLayer containsPoint:point]) {
          NSLog(@"Inside Blue Layer");
      } else {
          NSLog(@"Inside White Layer");
      }
   }
}

可以看到要想使用containsPoint方法必须要先转换坐标系,这样做还是有点麻烦的。好在我们还有hitTest方法可以用。hitTest方法同样需要传入一个点,但是他的返回值不再是布尔值。而是一个可以为空的CALayer。

- (nullable CALayer *)hitTest:(CGPoint)p;

当我们传入一个点,这个点在哪一个layer上就会返回这个layer,如果在这个layer的子图层上则会返回子图层,如果这个点在最外面图层的范围之外,则返回nil。使用hitTest方法之后上面的代码可以改成这样:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
  CGPoint point = [[touches anyObject] locationInView:self.view];
  CALayer *layer = [self.layerView.layer hitTest:point];
  if (layer == self.blueLayer) {
      NSLog(@"Inside Blue Layer");
  } else if (layer == self.layerView.layer) {
      NSLog(@"Inside White Layer");
  }
}

代码看起来比之前的好理解多了,而且也变得更简洁。这次就写这么多吧。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容