iOS自定义控件二

    xiaoxiao2021-12-14  17

    iOS自定义控件二

    Drawing with Layers

    本文内容,来自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

    内容来自Advanced Layers

    创建RingTip,RingTip是一个带有阴影的layer 大致思路如下: 1.tipLayer是个CAShapeLayer

    2.添加shadowLayer,阴影layer

    3.给shadowLayer设置遮罩shadowMaskLayer

    RingTip的完整代码如下:

    import UIKit public 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 UIKit import XCPlayground class 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 } } } } //: Values extension 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 } } } //: Colors extension 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://ju.6miu.com/read-964411.html

    最新回复(0)