美文网首页
iOS核心动画(二)

iOS核心动画(二)

作者: Rathen | 来源:发表于2017-11-26 10:00 被阅读24次

    图层几何学

    主要介绍图层内部是如何根据付图层和兄弟图层来控制位置和尺寸,还有如何管理图层的几何结构,以及它是如何被自动调整和自动布局影响的。

    布局

    UIView有三个比较重要的布局属性frameboundscenter
    CALayer对应的叫做frameboundsposition.
    frame代表了图层的外部坐标(也就是在父图层上占据的空间)
    bounds是内部坐标({0,0}是图层的左上角)
    center、position都代表了相对于父图层anchorPoint所在的位置。

    UIView和CALayer的坐标系.png
    操纵视图的frame,实际上是改变视图下CALayer的frame。

    锚点

    图层的anchorPoint通过position来控制它的frame的位置,你可以认为anchorPoint是用来移动图层的把柄。
    anchorPoint用单位坐标来描述,也就是图层的相对坐标,图层左上角是{0,0},右下角是{1,1},默认坐标是{0.5,0.5}

    OC代码
    #import "ViewController.h"
    
    @interface ViewController ()
    
    @property (nonatomic, strong) UIView *secondHandView;
    @property (nonatomic, strong) UIView *minuteHandView;
    @property (nonatomic, strong) UIView *hourHandView;
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        CALayer *layer = [[CALayer alloc] init];
        layer.bounds = CGRectMake(0, 0, 150, 150);
        layer.position = self.view.center;
        UIImage *image = [UIImage imageNamed:@"clock"];
        layer.contents = (__bridge id)image.CGImage;
        [self.view.layer addSublayer:layer];
        
        CADisplayLink *link = [CADisplayLink displayLinkWithTarget:self selector:@selector(clockRun)];
        [link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
        
        
    }
    
    - (void)clockRun {
        
        
        NSTimeZone *tZone = [NSTimeZone localTimeZone];
        NSCalendar *calendar = [NSCalendar currentCalendar];
        NSDate *currentDate = [NSDate date];
        [calendar setTimeZone:tZone];
        
        NSDateComponents *currentTime = [calendar components:NSCalendarUnitSecond|NSCalendarUnitMinute|NSCalendarUnitHour|NSCalendarUnitTimeZone fromDate:currentDate];
        CGFloat angle =  (M_PI * 2 / 60) * currentTime.second;
        
        self.secondHandView.transform = CGAffineTransformMakeRotation(angle);
        
        CGFloat minuteAngle = (M_PI * 2 / 60) * currentTime.minute;
        self.minuteHandView.transform = CGAffineTransformMakeRotation(minuteAngle);
        
        CGFloat hourAngle = (M_PI * 2 / 12) *currentTime.hour;
        self.hourHandView.transform = CGAffineTransformMakeRotation(hourAngle);
        
        
        
    }
    
    - (UIView *)secondHandView {
        if (_secondHandView == nil) {
            UIView *view = [[UIView alloc] init];
            view.backgroundColor = [UIColor redColor];
            view.bounds = CGRectMake(0, 0, 1, 60);
            view.center = self.view.center;
            view.layer.anchorPoint = CGPointMake(0.5, 1);
            [self.view addSubview:view];
            _secondHandView = view;
        }
        return _secondHandView;
    }
    
    - (UIView *)minuteHandView {
        if (_minuteHandView == nil) {
            UIView *view = [[UIView alloc] init];
            view.backgroundColor = [UIColor grayColor];
            view.bounds = CGRectMake(0, 0, 2, 60);
            view.center = self.view.center;
            view.layer.anchorPoint = CGPointMake(0.5, 1);
            [self.view addSubview:view];
            _minuteHandView = view;
        }
        return _minuteHandView;
    }
    
    - (UIView *)hourHandView {
        if (_hourHandView == nil) {
            UIView *view = [[UIView alloc] init];
            view.backgroundColor = [UIColor blackColor];
            view.bounds = CGRectMake(0, 0, 3, 60);
            view.center = self.view.center;
            view.layer.anchorPoint = CGPointMake(0.5, 1);
            [self.view addSubview:view];
            _hourHandView = view;
        }
        return _hourHandView;
    }
    
    
    - (void)didReceiveMemoryWarning {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }
    
    
    Swift代码
    import UIKit
    
    class ViewController: UIViewController {
    
        override func viewDidLoad() {
            super.viewDidLoad()
            
            let layer = CALayer()
            layer.bounds = CGRect(x: 0, y: 0, width: 150, height: 150)
            layer.position = self.view.center
            let image = UIImage(named:"clock")
            layer.contents = image?.cgImage
            view.layer .addSublayer(layer)
            
            let link = CADisplayLink(target: self, selector: #selector(clockRun))
            //将创建的CADisplayLink加入到主线程中
            link.add(to: RunLoop.main, forMode: RunLoopMode.defaultRunLoopMode)
            
            
        }
        
       @objc private func clockRun()   {
            let tZone = NSTimeZone.local
            var calendar = NSCalendar.current
            let currentDate = Date()
            calendar.timeZone = tZone
            
            let currentTime = calendar.dateComponents([Calendar.Component.hour,Calendar.Component.minute,Calendar.Component.second], from: currentDate)
            //设置秒针
            let angle = Double(currentTime.second!) * (Double.pi * 2 / 60);
            secondHandView.transform = CGAffineTransform(rotationAngle: CGFloat(angle));
            
            //设置分针
            let minuteAngle = Double (currentTime.minute!) * (Double.pi * 2.0 / 60)
            
            minuteHandView.transform = CGAffineTransform(rotationAngle: CGFloat(minuteAngle))
            
            //设置时针
            let hourAngle = Double (currentTime.hour!) * (Double.pi * 2.0 / 12)
            
            hourHandView.transform = CGAffineTransform(rotationAngle: CGFloat(hourAngle))
        }
        
        //秒针
        lazy var secondHandView : UIView = {
            let secondHandView = UIView();
            secondHandView.backgroundColor = UIColor.red
            secondHandView.bounds = CGRect(x: 0, y: 0, width: 1, height: 60)
            //修改锚点
            secondHandView.center = view.center;
            secondHandView.layer.anchorPoint = CGPoint(x: 0.5, y: 1)
           view.addSubview(secondHandView)
            return secondHandView;
        }()
        
        lazy var minuteHandView : UIView = {
            //设置分针针
            let minuteHandView = UIView()
            minuteHandView.backgroundColor = UIColor.gray
            minuteHandView.bounds = CGRect(x: 0, y: 0, width: 2, height: 60)
            //修改锚点
            minuteHandView.center = view.center;
            minuteHandView.layer.anchorPoint = CGPoint(x: 0.5, y: 1)
            view.addSubview(minuteHandView)
            return minuteHandView
        }()
        //时针
        lazy var hourHandView : UIView = {
            //设置时针
            let hourHandView = UIView()
            hourHandView.backgroundColor = UIColor.black
            hourHandView.bounds = CGRect(x: 0, y: 0, width: 3, height: 60)
            //修改锚点
            hourHandView.center = view.center;
            hourHandView.layer.anchorPoint = CGPoint(x: 0.5, y: 1)
            view.addSubview(hourHandView)
            return hourHandView
        }()
    
        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
            // Dispose of any resources that can be recreated.
        }
    
    
    }
    
    
    1.png

    坐标系

    和视图一样,图层在图层树中也是相当于父图层按照层级关系放置,一个层级的position依赖于它的父层级的bounds,如果父图层发生的变化,它所有的子图层都会移动。
    和UIView严格的二维坐标不同,CALayer存在于一个三维k空间当中。除了我们讨论过的position和anchorPoint属性外,CALayer还有两个属性zPosition和anchorPointZ,二者都是在Z轴上描述图层位置的浮点类型。

    相关文章

      网友评论

          本文标题:iOS核心动画(二)

          本文链接:https://www.haomeiwen.com/subject/sricbxtx.html