与UIScrollView同步UIView CALayer绘制

问题描述 投票:0回答:1

我正在尝试制作一个可以在 pdf 上绘图的应用程序。要求图形形状绑定到页面上的特定位置。

为了解决这个问题,我使用PDFView和CALayer,监听内部UIScrollView的scrollViewDidScroll和scrollViewDidZoom的事件来重绘CALayer

我找到了两种绘画方法:

  1. 使用CAShapeLayer的“path”属性(示例1
  2. 重写 CALayer 的“draw”方法(示例 2

我注意到在第二种情况下,当滚动或缩放时,图形明显落后于 pdf 文档。

问题是,“path”方法到底有什么“魔力”,可以实现即时重画?是否可以修改“draw”方法,使其与“path”同步工作?那么“路径”方法未来的稳定性如何?

查看要编译和运行的项目:https://github.com/alzhuravlev/DrawTest.git

示例代码:

class AnnotationsLayer: CAShapeLayer {
...

  override func draw(in ctx: CGContext) {
        guard let backgroundView else { return }

        ctx.setFillColor(UIColor.red.withAlphaComponent(0.4).cgColor)
        ctx.setStrokeColor(UIColor.green.withAlphaComponent(1.0).cgColor)
        ctx.setLineWidth(10)

        backgroundView.pages.forEach { page in
            let p1 = backgroundView.convert(point: CGPoint(x: page.size.width/3, y: page.size.height/3), from: page.index)
            let p2 = backgroundView.convert(point: CGPoint(x: page.size.width/3*2, y: page.size.height/3*2), from: page.index)

            ctx.move(to: CGPoint(x: p1.x, y: p1.y))
            ctx.addLine(to: CGPoint(x: p2.x, y: p1.y))
            ctx.addLine(to: CGPoint(x: p2.x, y: p2.y))
            ctx.addLine(to: CGPoint(x: p1.x, y: p2.y))
            ctx.closePath()
        }


        ctx.drawPath(using: CGPathDrawingMode.fillStroke)
    }

    func rebuildShapes() {
        
        // false - example 1
        // true - example 2
        if (false) { 
            setNeedsDisplay()
        } else {
            
            guard let backgroundView else { return }
            
            let p = UIBezierPath()
            
            fillColor = UIColor.red.withAlphaComponent(0.4).cgColor
            
            strokeColor = UIColor.green.withAlphaComponent(1.0).cgColor
            lineWidth = 10
            
            backgroundView.pages.forEach { page in
                let p1 = backgroundView.convert(point: CGPoint(x: page.size.width/3, y: page.size.height/3), from: page.index)
                let p2 = backgroundView.convert(point: CGPoint(x: page.size.width/3*2, y: page.size.height/3*2), from: page.index)
                
                p.move(to: CGPoint(x: p1.x, y: p1.y))
                p.addLine(to: CGPoint(x: p2.x, y: p1.y))
                p.addLine(to: CGPoint(x: p2.x, y: p2.y))
                p.addLine(to: CGPoint(x: p1.x, y: p2.y))
                p.close()
            }
            
            path = p.cgPath
        }
    }
...
ios uiscrollview uikit calayer cashapelayer
1个回答
0
投票

根据OP的评论,这是我将使用的内容,而不是在

draw(in ctx: CGContext)
中覆盖
CAShapeLayer

class AnnotationsView: UIView {
    var backgroundView: BackgroundView? {
        didSet {
            print("did set background view")
        }
    }
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    func commonInit() {
        backgroundColor = .clear
    }
    func rebuildShapes() {
        setNeedsDisplay()
    }
    
    override func draw(_ rect: CGRect) {
        super.draw(rect)
        
        guard let backgroundView else { return }
        
        let p = UIBezierPath()
        
        let fillColor = UIColor.red.withAlphaComponent(0.4)
        
        let strokeColor = UIColor.green.withAlphaComponent(1.0)
        let lineWidth = 10
        
        backgroundView.pages.forEach { page in
            let p1 = backgroundView.convert(point: CGPoint(x: page.size.width/3, y: page.size.height/3), from: page.index)
            let p2 = backgroundView.convert(point: CGPoint(x: page.size.width/3*2, y: page.size.height/3*2), from: page.index)
            let r: CGRect = .init(x: p1.x, y: p1.y, width: p2.x - p1.x, height: p2.y - p1.y)
            if r.intersects(rect) {
                p.append(.init(rect: r))
            }
        }
        
        fillColor.setFill()
        p.fill()
        strokeColor.setStroke()
        p.lineWidth = CGFloat(lineWidth)
        p.stroke()
    }
}

无需添加任何层。

© www.soinside.com 2019 - 2024. All rights reserved.