UIScrollView zooming and affected CAShapeLayer lineWidth

549 Views Asked by At

I have a bunch of CAShapeLayers built with UIBezierPath and stored inside of UIScrollView.

I wonder if there any way to keep the lineWidth of CAShapeLayer's path away from scaling when UIScrollView is zoomed over 100%. I mean applying the UIScrollView's transformation rules to CAShapeLayer, but keep the path's widh the same as it used to be on 1.0 zoomScale. (So when the layer with 1pt path lineWidth will be zoomed to 300%, the lineWidth of the layer on @2x device won't become 6px height, but will keep the height of 2px)

1

There are 1 best solutions below

4
GaétanZ On
class ViewController : UIViewController, UIScrollViewDelegate {

    private lazy var scrollView = UIScrollView()
    private lazy var contentView = UIView()
    private lazy var shapeLayer = CAShapeLayer()
    private let lineWidth: CGFloat = 1

    override func loadView() {
        view = UIView()
        view.addSubview(scrollView)
        scrollView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        scrollView.addSubview(contentView)
        scrollView.minimumZoomScale = 1.0
        scrollView.maximumZoomScale = 2.0
        scrollView.delegate = self
        contentView.backgroundColor = .red
        let viewSize = CGSize(width: 400, height: 400)
        scrollView.contentSize = viewSize
        contentView.frame = CGRect(x: 0, y: 0, width: viewSize.width, height: viewSize.height)
        setUpShapeLayer(in: viewSize)
    }

    //MARK: - UIScrollViewDelegate

    func scrollViewDidZoom(_ scrollView: UIScrollView) {
        shapeLayer.lineWidth = lineWidth * 1 / scrollView.zoomScale
    }

    func viewForZooming(in scrollView: UIScrollView) -> UIView? {
        return contentView
    }

    //MARK: - Private

    private func setUpShapeLayer(in size: CGSize) {
        shapeLayer.fillColor = UIColor.white.cgColor
        shapeLayer.strokeColor = UIColor.black.cgColor
        shapeLayer.lineWidth = lineWidth
        contentView.layer.addSublayer(shapeLayer)
        let shapeSize = CGSize(width: 200, height: 200)
        let shapeBounds = CGRect(origin: .zero, size: shapeSize)
        shapeLayer.bounds.size = shapeSize
        shapeLayer.path = UIBezierPath(ovalIn: shapeBounds).cgPath
        shapeLayer.position = CGPoint(x: size.width / 2, y: size.height / 2)
    }
}

Is it what you want ?