
iOS自定义控件二
发布日期:2022-03-18 08:27:41
浏览次数:19
分类:技术文章
本文共 10986 字,大约阅读时间需要 36 分钟。
iOS自定义控件二
Drawing with Layers
本文内容,来自
本例子是使用Layer来创建一个RingLayer
,最终的效果如下:
大致思路是:
1.后面的灰色背景backgroundLayer
2.前面的foregroundLayer
,foregroundLayer
上添加一个gradientLayer
,相当于是一个渐变的layer。
3.给foregroundLayer
设置Mask为foregroundMask
,foregroundMask
为CAShapeLayer
4.旋转gradientLayer
5.如上图,渐变开始的部分还有突变,在foregroundLayer
,再添加上一个ringTipLayer
6.旋转ringTipLayer
RingLayer
的代码如下:
public class RingLayer : CALayer { private let angleOffsetForZero = CGFloat(-M_PI_2) private lazy var gradientLayer : CircularGradientLayer = { let gradLayer = CircularGradientLayer() gradLayer.colors = self.ringColors return gradLayer }() private lazy var backgroundLayer : CAShapeLayer = { let layer = CAShapeLayer() layer.strokeColor = self.ringBackgroundColor layer.lineWidth = self.ringWidth layer.fillColor = nil return layer }() private lazy var foregroundLayer : CALayer = { let layer = CALayer() layer.addSublayer(self.gradientLayer) layer.addSublayer(self.ringTipLayer) layer.mask = self.foregroundMask return layer }() private lazy var ringTipLayer : CAShapeLayer = { let layer = CAShapeLayer() layer.strokeColor = self.ringColors.0 layer.lineWidth = self.ringWidth layer.fillColor = nil layer.lineCap = kCALineCapRound return layer }() //mask遮罩 private lazy var foregroundMask : CAShapeLayer = { let layer = CAShapeLayer() layer.strokeColor = UIColor.blackColor().CGColor layer.fillColor = UIColor.clearColor().CGColor layer.lineWidth = self.ringWidth layer.lineCap = kCALineCapRound return layer }() //:- Public API var ringWidth: CGFloat = 40.0 { didSet { backgroundLayer.lineWidth = ringWidth ringTipLayer.lineWidth = ringWidth foregroundMask.lineWidth = ringWidth preparePaths() } } var value: CGFloat = 0.0 { didSet { preparePaths() //旋转 ringTipLayer.setValue(angleForValue(value), forKeyPath: "transform.rotation.z") gradientLayer.setValue(angleForValue(value), forKeyPath: "transform.rotation.z") } } //颜色 var ringColors: (CGColorRef, CGColorRef) = (UIColor.redColor().CGColor, UIColor.redColor().darkerColor.CGColor) { didSet { gradientLayer.colors = ringColors ringTipLayer.strokeColor = ringColors.0 } } var ringBackgroundColor: CGColorRef = UIColor.darkGrayColor().CGColor { didSet { backgroundLayer.strokeColor = ringBackgroundColor } } //:- Initialisation public override init() { super.init() sharedInitialization() } required public init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) sharedInitialization() }}extension RingLayer { private func sharedInitialization() { backgroundColor = UIColor.blackColor().CGColor //添加sublayer [backgroundLayer, foregroundLayer].forEach { self.addSublayer($0) } self.value = 0.8 } //重写方法 public override func layoutSublayers() { super.layoutSublayers() if backgroundLayer.bounds != bounds { for layer in [backgroundLayer, foregroundLayer, foregroundMask, gradientLayer, ringTipLayer] { layer.bounds = bounds layer.position = center } preparePaths() } }}extension RingLayer { //半径 private var radius : CGFloat { return (min(bounds.width, bounds.height) - ringWidth) / 2.0 } //路径 private func preparePaths() { backgroundLayer.path = backgroundPath foregroundMask.path = maskPathForValue(value) ringTipLayer.path = UIBezierPath(arcCenter: center, radius: radius, startAngle: -0.01, endAngle: 0, clockwise: true).CGPath } private var backgroundPath : CGPathRef { return UIBezierPath(arcCenter: center, radius: radius, startAngle: 0, endAngle: 2 * CGFloat(M_PI), clockwise: true).CGPath } private func maskPathForValue(value: CGFloat) -> CGPathRef { return UIBezierPath(arcCenter: center, radius: radius, startAngle: angleOffsetForZero, endAngle: angleForValue(value), clockwise: true).CGPath } //value对应角度 private func angleForValue(value: CGFloat) -> CGFloat { return value * 2 * CGFloat(M_PI) + angleOffsetForZero }}
Advanced Layers
内容来自
创建RingTip
,RingTip
是一个带有阴影的layer
CAShapeLayer
2.添加shadowLayer
,阴影layer
3.给shadowLayer
设置遮罩shadowMaskLayer
RingTip
的完整代码如下:
import UIKitpublic class RingTip : CALayer { //MARK:- Constituent Layers private lazy var tipLayer : CAShapeLayer = { let layer = CAShapeLayer() layer.lineCap = kCALineCapRound layer.lineWidth = self.ringWidth return layer }() private lazy var shadowLayer : CAShapeLayer = { let layer = CAShapeLayer() layer.lineCap = kCALineCapRound layer.lineWidth = self.ringWidth layer.strokeColor = UIColor.blackColor().CGColor layer.shadowColor = UIColor.blackColor().CGColor layer.shadowOffset = .zero layer.shadowRadius = 12.0 layer.shadowOpacity = 1.0 layer.mask = self.shadowMaskLayer return layer }() private lazy var shadowMaskLayer : CAShapeLayer = { let layer = CAShapeLayer() layer.strokeColor = UIColor.blackColor().CGColor layer.lineCap = kCALineCapButt layer.lineWidth = self.ringWidth return layer }() //MARK:- Utility Properties private var radius : CGFloat { return (min(bounds.width, bounds.height) - ringWidth) / 2.0 } private var tipPath : CGPathRef { return UIBezierPath(arcCenter: center, radius: radius, startAngle: -0.01, endAngle: 0, clockwise: true).CGPath } private var shadowMaskPath : CGPathRef { return UIBezierPath(arcCenter: center, radius: radius, startAngle: 0, endAngle: CGFloat(M_PI_2), clockwise: true).CGPath } //MARK:- API Properties public var color: CGColorRef = UIColor.redColor().CGColor { didSet { tipLayer.strokeColor = color } } public var ringWidth: CGFloat = 40.0 { didSet { tipLayer.lineWidth = ringWidth shadowLayer.lineWidth = ringWidth shadowMaskLayer.lineWidth = ringWidth preparePaths() } } //MARK:- Initialisation public override init() { super.init() sharedInitialisation() } public required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) sharedInitialisation() } private func sharedInitialisation() { addSublayer(shadowLayer) addSublayer(tipLayer) color = UIColor.redColor().CGColor preparePaths() } //MARK:- Lifecycle Overrides override public func layoutSublayers() { for layer in [tipLayer, shadowLayer, shadowMaskLayer] { layer.bounds = bounds layer.position = center } preparePaths() } //MARK:- Utility methods private func preparePaths() { tipLayer.path = tipPath shadowLayer.path = tipPath shadowMaskLayer.path = shadowMaskPath }}
然后用RingTip
替换ringTipLayer
private lazy var ringTipLayer : RingTip = { let layer = RingTip() layer.color = self.ringColors.0 layer.ringWidth = self.ringWidth return layer }()
之后效果如下:
最后创建3个ring
效果如下:完整代码如下:
import UIKitimport XCPlaygroundclass ThreeRingView : UIView { //枚举 private enum RingIndex : Int { case Inner = 0 case Middle = 1 case Outer = 2 } private let rings : [RingIndex : RingLayer] = [.Inner : RingLayer(), .Middle : RingLayer(), .Outer : RingLayer()] override init(frame: CGRect) { super.init(frame: frame) sharedInitialization() } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) sharedInitialization() } //重写layoutSubviews override func layoutSubviews() { super.layoutSubviews() drawLayers() } private func sharedInitialization() { backgroundColor = UIColor.blackColor() for (_, ring) in rings { //添加layer layer.addSublayer(ring) ring.backgroundColor = UIColor.clearColor().CGColor ring.ringBackgroundColor = ringBackgroundColor.CGColor ring.ringWidth = ringWidth } // Set the default values for (color, (index, ring)) in zip([UIColor.hrPinkColor, UIColor.hrGreenColor, UIColor.hrBlueColor], rings) { //设置颜色 setColorForRing(index, color: color) ring.value = 0.0 } } private func drawLayers() { let size = min(bounds.width, bounds.height) for (index, ring) in rings { //大小和位置 let curSize = size - CGFloat(index.rawValue) * ( ringWidth + ringPadding ) * 2.0 ring.bounds = CGRect(x: 0, y: 0, width: curSize, height: curSize) ring.position = layer.position } } //: API Properties var ringWidth : CGFloat = 20.0 { didSet { drawLayers() for (_, ring) in rings { ring.ringWidth = ringWidth } } } var ringPadding : CGFloat = 1.0 { didSet { drawLayers() } } var ringBackgroundColor : UIColor = UIColor.darkGrayColor() { didSet { for (_, ring) in rings { ring.ringBackgroundColor = ringBackgroundColor.CGColor } } }}//: Valuesextension ThreeRingView { var innerRingValue : CGFloat { get { return rings[.Inner]?.value ?? 0 } set(newValue) { rings[.Inner]?.value = newValue } } var middleRingValue : CGFloat { get { return rings[.Middle]?.value ?? 0 } set(newValue) { rings[.Middle]?.value = newValue } } var outerRingValue : CGFloat { get { return rings[.Outer]?.value ?? 0 } set(newValue) { rings[.Outer]?.value = newValue } }}//: Colorsextension ThreeRingView { var innerRingColor : UIColor { get { return colorForRing(.Inner) } set(newColor) { setColorForRing(.Inner, color: newColor) } } var middleRingColor : UIColor { get { return UIColor.clearColor() } set(newColor) { setColorForRing(.Middle, color: newColor) } } var outerRingColor : UIColor { get { return UIColor.clearColor() } set(newColor) { setColorForRing(.Outer, color: newColor) } } private func colorForRing(index: RingIndex) -> UIColor { return UIColor(CGColor: rings[index]!.ringColors.0) } private func setColorForRing(index: RingIndex, color: UIColor) { rings[index]?.ringColors = (color.CGColor, color.darkerColor.CGColor) }}
转载地址:https://windzen.blog.csdn.net/article/details/53435252 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!
发表评论
最新留言
哈哈,博客排版真的漂亮呢~
[***.90.31.176]2023年05月24日 12时10分51秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
最新文章
composer升级_Composer 2.0 发布带来的性能优化、新特性和升级指南
2019-12-02 03:25:30
isight参数优化理论与实例详解_案例1(ISIGHT使用须知)
2019-12-02 03:25:30
dockerfile构建镜像的命令_Dockerfile构建指南怎样构建一个适用企业级的镜像
2019-12-02 03:25:30
el-form input 数字_浅析数字时代下的两种转型
2019-12-02 03:25:31
步步高vivo高通解锁工具_2020高通骁龙技术峰会预告:骁龙875揭开面纱 小米三星再争首发...
2019-12-02 03:25:31
arcgis删除栅格数据波段_【实用】62个关于ArcGIS的常用技巧
2019-12-02 03:25:31
ab编程软件studio5000_AB PLC | STUDIO 5000仿真软件大合集
2019-12-02 03:25:31
sql server 中获取前一天日期_SQL高级知识——DBLINK
2019-12-02 03:25:28
sqlserver执行了drop table 恢复没有备份_又一程序员删库跑路被拘留?教你如何一键恢复!...
2019-12-02 03:25:28
高位在前低位在后是啥意思_深度被套后应该如何补仓?终于有人把它讲明白了,精髓都在这里,学会了被套将与你永远无缘...
2019-12-02 03:25:28
安装了email模块还是报错_神级编辑器Grid studio 安装教程「Windows篇」
2019-12-02 03:25:29
zabbix 安装_【教程】手把手zabbix安装教程!
2019-12-02 03:25:29
win7语音识别组件安装_如何在WIN10上完美(曲折)的安装T3普及版?
2019-12-02 03:25:29
ubuntu 最新提权漏洞_利用mssql受信用数据库提权
2019-12-02 03:25:29
c++ 怎么读取rtf文件_C语言零基础入门文件
2019-12-02 03:25:29
python numpy 转置_python numpy.transpose(np.T) 详解
2019-12-02 03:25:27
springboot修改端口号_SpringBoot系列教程11--小花样之SpringBoot其他常用配置
2019-12-02 03:25:27
houdini节点大全中文手册_【技术贴】武林秘籍在此!大咖座谈虚幻引擎制作影视动画经验!...
2019-12-02 03:25:27
python四级词汇采集_python+NLTK 自然语言学习处理四:获取文本语料和词汇资源
2019-12-02 03:25:27
python分析红楼梦中人物形象_红楼梦中贾宝玉的人物形象分析
2019-12-02 03:25:27