OC知识梳理 UIView CALayer之 图层几何学

几个概念 

布局

UIView有三个重要的布局属性:frame bounds center;CALayer有frame bounds position.

Frame 代表的是占据父视图的位置和大小,bounds是内部坐标{0,0,width,height},center和position是相对父视图中心点的位置.当操作视图的frame实际上是改变位于视图下方CALayer的frame,不能够独立于图层之外改变的视图的frame.真正改变的frame是根据bounds position transform计算而来,同理改变frame值同样会影响到他们的值.

锚点

anchorPoint就是位于图层的中心点,通过UIView的属性center进行

这里会以一个大家所熟悉的钟表demo来说明

//

//  TestView.m

//  CGLine

//

//  Created by edz on 2020/1/26.

//  Copyright © 2020 mende. All rights reserved.

//

 

#import "TestView.h"

 

#define kAngleToRadion(angle) ((angle) / 180.0 * M_PI)

 

@interface TestView ()

{

    __weak NSTimer *_timer;

}

@property (nonatomic,strong) CALayer *hourLayer;

@property (nonatomic,strong) CALayer *minuteLayer;

@property (nonatomic,strong) CALayer *secondLayer;

@end

 

@implementation TestView

 

 

- (instancetype)initWithFrame:(CGRect)frame imageName:(NSString *)imageName{

    

    self = [super initWithFrame:frame];

    if (self) {

        UIImage *image = [UIImage imageNamed:imageName];

        self.layer.contents = (__bridge id)(image.CGImage);

        CGFloat selfWidth = self.frame.size.width;

    

        //实例化时分秒图层

        self.hourLayer = [self layerWithBgColor:[UIColor blackColor] size:CGSizeMake(3, selfWidth/2-40)];

        self.minuteLayer = [self layerWithBgColor:[UIColor blackColor] size:CGSizeMake(3, selfWidth/2 - 20)];

        self.secondLayer = [self layerWithBgColor:[UIColor redColor] size:CGSizeMake(1, selfWidth/2 - 20)];

        

        NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timeUpdate:) userInfo:nil repeats:YES];

        [[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

        _timer = timer;

        

        [self buildUI];

    }

    return self;

}

 

- (void)releaseTimer{

    [_timer invalidate];

    _timer = nil;

}

 

- (void)timeUpdate:(NSTimer *)timer{

    

    [self buildUI];

}

 

- (void)buildUI{

    //获取时间

    NSCalendar *calendar = [NSCalendar currentCalendar];

    

    NSDateComponents *date = [calendar components:NSCalendarUnitSecond|NSCalendarUnitMinute|NSCalendarUnitHour fromDate:[NSDate date]];

    NSInteger second = date.second;

    NSInteger minute = date.minute;

    NSInteger hour = date.hour;

    

    CGFloat perHourMove = 360.0 / 12.0;

    CGFloat hourAngle = hour * perHourMove + minute*(1.0/60.0)*perHourMove;

    self.hourLayer.transform =  CATransform3DMakeRotation(kAngleToRadion(hourAngle), 0, 0, 1);

    

    CGFloat minuteAngle = minute * 360.0 / 60.0;

    self.minuteLayer.transform = CATransform3DMakeRotation(kAngleToRadion(minuteAngle), 0, 0, 1);

    

    CGFloat secondAngle = second * 360.0 / 60.0;

    self.secondLayer.transform = CATransform3DMakeRotation(kAngleToRadion(secondAngle), 0, 0, 1);

    

}

 

- (void)dealloc{

    

    [_timer invalidate];

}

 

- (CALayer *)layerWithBgColor:(UIColor *)color size:(CGSize)size{

    CALayer *layer = [CALayer layer];

    layer.backgroundColor = color.CGColor;

    layer.anchorPoint = CGPointMake(0.5, 0.9);

    

    //设置position为中心

    layer.position = CGPointMake(self.frame.size.width/2, self.frame.size.height/2);

    //hour min s的长度

    layer.bounds = CGRectMake(0, 0, size.width, size.height);

    layer.cornerRadius = 4;

    [self.layer addSublayer:layer];

    return layer;

}

 

@end

Z坐标轴

与UIView严格的二维坐标不同,CALayer存在一个三维空间当中,有zPosition,anchorPointZ,当出现三维空间于东和旋转图层的时候需要用到zPosition来改变图层的显示顺序.

Hit Testing

CALayer并不关心任何响应链事件,所以不能直接处理触摸事件和手续,但是它有一系列方法帮你处理事件,-containsPosition 和hitTest

-constainsPoint:接受一个在本图层坐标系下的CGpoint 返回YES

从大到小一点点捕获到触摸点的位置

 

#import "ViewController.h"

#import "TestView.h"

 

@interface ViewController ()<CALayerDelegate>

{

    CGContextRef _currentContext;

}

@property (nonatomic, strong) UIView *layerView;

@property (nonatomic, strong) CALayer *blueLayer;

@end

 

@implementation ViewController

 

- (void)viewDidLoad {

    [super viewDidLoad];

    self.view.backgroundColor = [UIColor grayColor];

  

    _layerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 400, 400)];

    [_layerView setBackgroundColor:[UIColor redColor]];

    _layerView.clipsToBounds = YES;

    [self.view addSubview:_layerView];

    self.blueLayer = [CALayer layer];

    self.blueLayer.frame = CGRectMake(50, 50, 100, 100);

    self.blueLayer.backgroundColor = [UIColor blueColor].CGColor;

    [self.layerView.layer addSublayer:self.blueLayer];

 

   

}

 

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{

    

    CGPoint point = [[touches anyObject] locationInView:self.view];

    

    point = [self.layerView.layer convertPoint:point fromLayer:self.view.layer];

    if ([self.layerView.layer containsPoint:point]) {

        

        point = [self.blueLayer convertPoint:point fromLayer:self.layerView.layer];

        if ([self.blueLayer containsPoint:point]) {

             NSLog(@"蓝色图层触摸到了");

        }

        else{

            NSLog(@"红色图层触摸到了");

        }

        

        

    }

    

}

-hitTest:接受一个在本图层坐标系下的CGpoint  返回图层本身

 

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{

    

    CGPoint point = [[touches anyObject] locationInView:self.view];

    CALayer *layer = [self.layerView.layer hitTest:point];

    if ([layer isEqual:self.blueLayer]) {

        NSLog(@"蓝色图层触摸到了");

    }else{

        NSLog(@"红色图层触摸到了");

    }

}

反观用hitTest更加简洁一些

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值