参考:
一、直接做动画
- 新建项目clock
- 加载表盘图片。
在viewDidLoad
中添加:let dialLayer = CALayer() dialLayer.bounds = CGRect(x: 0, y: 0, width: 150, height: 150) dialLayer.position = self.view.center dialLayer.contents = UIImage(named: "clock")?.cgImage view.layer.addSublayer(dialLayer)
- 懒加载秒针、分针、时针视图。懒加载机制是Swift中一种存储属性:延迟存储属性,具体可擦看 以撸代码的形式学习Swift-10:Properties
// 秒针 lazy var secondHandView: UIView = { let secondHandView = UIView() secondHandView.backgroundColor = UIColor.red secondHandView.bounds = CGRect(x: 0, y: 0, width: 1, height: 60) secondHandView.layer.anchorPoint = CGPoint(x: 0.5, y: 1) return secondHandView }() // 分针 lazy var minuteHandView: UIView = { let minuteHandView = UIView() minuteHandView.backgroundColor = UIColor.darkGray minuteHandView.bounds = CGRect(x: 0, y: 0, width: 3, height: 60) minuteHandView.layer.anchorPoint = CGPoint(x: 0.5, y: 1) return minuteHandView }() // 时针 lazy var hourHandView: UIView = { let hourHandView = UIView() hourHandView.backgroundColor = UIColor.darkGray hourHandView.bounds = CGRect(x: 0, y: 0, width: 3, height: 45) hourHandView.layer.anchorPoint = CGPoint(x: 0.5, y: 1) return hourHandView }()
- 把秒针、分针、时针添加到view中。在
viewDidLoad
中添加:secondHandView.center = view.center self.view.addSubview(secondHandView) minuteHandView.center = view.center self.view.addSubview(minuteHandView) hourHandView.center = view.center self.view.addSubview(hourHandView)
- 创建
CADisplayLink
,并将其添加到主线程中。在viewDidLoad
中添加:let link = CADisplayLink(target: self, selector: #selector(ViewController.clockRunning)) link.add(to: RunLoop.main, forMode: .defaultRunLoopMode)
- 添加方法
clockRunning
:func clockRunning() { let tZone = TimeZone.current var calendar = Calendar.current let currentDate = Date() calendar.timeZone = tZone let currentTime = calendar.dateComponents([Calendar.Component.hour, Calendar.Component.minute, Calendar.Component.second], from: currentDate) // 根据当前秒、分、时数分别计算秒针、分针、时针偏转弧度 let secondAngle = CGFloat ( Double(currentTime.second!) * (Double.pi * 2.0 / 60) ) secondHandView.transform = CGAffineTransform(rotationAngle: secondAngle) let minuteAngle = CGFloat ( Double(currentTime.minute!) * (Double.pi * 2.0 / 60) ) minuteHandView.transform = CGAffineTransform(rotationAngle: minuteAngle) let hourAngle = CGFloat ( Double(currentTime.hour!) * (Double.pi * 2.0 / 12) ) hourHandView.transform = CGAffineTransform(rotationAngle: hourAngle) }
现在就完成了文章开头的效果。
二、代码说明
- 关于
anchorPoint
(锚点)
如果注释掉分针和时针视图,并且关掉动画效果和锚点设置:
// secondHandView.layer.anchorPoint = CGPoint(x: 0.5, y: 1)
// minuteHandView.center = view.center
// self.view.addSubview(minuteHandView)
// hourHandView.center = view.center
// self.view.addSubview(hourHandView)
// 创建CADisplayLink,并将其添加到主线程中
// let link = CADisplayLink(target: self, selector: #selector(ViewController.clockRunning))
// link.add(to: RunLoop.main, forMode: .defaultRunLoopMode)
加上secondHandView.layer.anchorPoint = CGPoint(x: 0.5, y: 1)
后:
anchorPoint
的官方描述:
Defines the anchor point of the layer's bounds rectangle. Animatable.
You specify the value for this property using the unit coordinate space. The default value of this property is (0.5, 0.5), which represents the center of the layer’s bounds rectangle.All geometric manipulations to the view occur about the specified point.
For example, applying a rotation transform to a layer with the default anchor point causes the layer to rotate around its center. Changing the anchor point to a different location would cause the layer to rotate around that new point.
anchorPoint
的值在 (0,0)
和 (1,1)
之间。默认是 (0.5, 0.5)
,代表锚点在中心位置。 (0,0)
和 (1,1)
分别代表左上角和右上角。
- 关于
CALayer
的属性position
和anchorPoint
-
position
类似UIView
的center
-
position
决定了layer在父视图上的位置 -
anchorPoint
决定了position
在自身的位置。All geometric manipulations to the view occur about the specified point.
- CADisplayLink 与 NSTimer
- CADisplayLink精确度高
- NSTimer占用系统资源较多
代码和图片位置: 89-Animation/clock