Search code examples
ioscalayerpixelcabasicanimation

iOS CALayer mask strange half pixel line


I need to cut transparent arc from 0 to pi through all text layer. Code give above below working fine except one thing. I have small width line while performing CABasicAnimation for masking CALayer and no strange line in idle state.

half pixel line image

Can't understand why it's showing because theoretically it doesn't have to be visible at all...

Here is my playground code:

import UIKit
import PlaygroundSupport

let rootView = UIView(frame: CGRect(x: 0, y: 0,
                                    width: 200,
                                    height: 200))
rootView.backgroundColor = .gray

let uiview = UIButton(frame: CGRect(x: 0,
                                  y: 0,
                                  width: 200,
                                  height: 200))
uiview.setTitle("H", for: .normal)
uiview.titleLabel?.font = UIFont.boldSystemFont(ofSize: 200)
uiview.setTitleColor(.black, for: .normal)
uiview.backgroundColor = UIColor.green
uiview.layer.cornerRadius = 100
uiview.layer.masksToBounds = true
rootView.addSubview(uiview)

let center = CGPoint(x: uiview.bounds.width / 2,
                     y: uiview.bounds.height / 2)

let path = UIBezierPath(arcCenter: center,
                        radius: 80,
                        startAngle: 0,
                        endAngle: .pi,
                        clockwise: true)
path.append(UIBezierPath(arcCenter: center,
                         radius: 78,
                         startAngle: -1,
                         endAngle: .pi,
                         clockwise: true))
path.append(UIBezierPath(rect: uiview.bounds))

let maskLayer = CAShapeLayer()
maskLayer.frame = uiview.bounds
maskLayer.path = path.cgPath
maskLayer.backgroundColor = UIColor.clear.cgColor
maskLayer.fillRule = kCAFillRuleEvenOdd
maskLayer.lineWidth = 0

uiview.layer.mask = maskLayer

let rotation = CABasicAnimation(keyPath: "transform.rotation")
rotation.fromValue = 0.0
rotation.toValue = Double.pi * 2
rotation.duration = 10
rotation.repeatCount = 2
maskLayer.add(rotation, forKey: nil)


PlaygroundPage.current.liveView = rootView

How can I solve this?


Solution

  • With a few small changes, like so:

    path.append(UIBezierPath(arcCenter: center,
                             radius: 78,
                             startAngle: .pi,
                             endAngle: 0,
                             clockwise: false))
    

    the last few seconds of the animation look like this:

    last few seconds of animation

    The two arc were misaligned to each other.

    So what changed:

    • the second arc got a start angle of PI

    • it got an end angle of 0

    • clockwise is set to false

    Is that what you're looking for?