Как обновить UIBezierPath и CAShapeLayer с помощью жеста панорамирования в UIView?

#swift #animation #draw #uibezierpath #cashapelayer

#swift #Анимация #рисовать #uibezierpath #cashapelayer

Вопрос:

»’

 import UIKit

class CanvasView: UIView {
    var circleViewTag = 1000
    var coordinatePoints: [String] = ["243,103","534,86","243,286","426,286"] {
        didSet {
            self.updateCoordinateArray()
            self.drawPoints()
        }
    }
    
    fileprivate var coordArray: [CGPoint] = []
    var shape = CAShapeLayer()
    var path = UIBezierPath()
    /*// Only override draw() if you perform custom drawing.
    // An empty implementation adversely affects performance during animation.
    override func draw(_ rect: CGRect) {
        // Drawing code
    }*/
    
    private func drawPoints() -> Void {
        CommonMethods.printLog("(coordinatePoints)")
        self.layer.addSublayer(shape)
        shape.opacity = 0.5
        shape.lineWidth = 2
        shape.lineJoin = CAShapeLayerLineJoin.miter
        shape.strokeColor = UIColor.white.cgColor
        shape.fillColor = UIColor(red: 1.0, green: 0.2, blue: 0.2, alpha: 0.2).cgColor
        
        if let firstCoord = self.coordArray.first {
            path.move(to: firstCoord)
        }
        for (index, cgPoint) in self.coordArray.enumerated() {
            self.drawCircularPoint(points: cgPoint)
            if index == 0 {
                continue
            }
            path.addLine(to: cgPoint)
        }
        path.close()
        shape.path = path.cgPath
        //self.drawLineBetweenPoints()
    }

    
    private func drawCircularPoint(points: CGPoint) -> Void {
        
        let circleView = UIView.init(frame: .zero)
        circleViewTag = circleViewTag   1
        circleView.tag = circleViewTag
        circleView.frame.size = CGSize.init(width: 30.0, height: 30.0)
        circleView.layer.cornerRadius = 15.0
        circleView.center = points
        circleView.backgroundColor = .random()
        
        let panGesture = UIPanGestureRecognizer(target: self, action: #selector(self.draggedView(_:)))
        panGesture.view?.tag = circleView.tag
        circleView.isUserInteractionEnabled = true
        circleView.addGestureRecognizer(panGesture)
        
        self.addSubview(circleView)
    }
    
    @objc func draggedView(_ sender:UIPanGestureRecognizer){
        guard let getTag = sender.view?.tag else { return }
        if let viewToDrag = self.viewWithTag(getTag) as? UIView {
            var currentPoint: CGPoint = .zero
            if path.contains(viewToDrag.center) {
                print("YES")
                
                currentPoint = path.currentPoint
                
            }
            
            let translation = sender.translation(in: self)
            viewToDrag.center = CGPoint(x: viewToDrag.center.x   translation.x, y: viewToDrag.center.y   translation.y)
            sender.setTranslation(CGPoint.zero, in: self)
            
            if sender.state == .began amp;amp; currentPoint != .zero {
                let coordinateIndex =  self.coordArray.firstIndex { (cgpoint) -> Bool in
                    if currentPoint == cgpoint {
                        return true
                    }
                    return false
                }
                
                if coordinateIndex != nil {
                    self.coordArray[coordinateIndex!] = viewToDrag.center
                    self.shape.removeFromSuperlayer()
                    self.path.removeAllPoints()
                    self.setNeedsDisplay()
                    
                    self.layer.addSublayer(self.shape)
                    self.shape.opacity = 0.5
                    self.shape.lineWidth = 2
                    self.shape.lineJoin = CAShapeLayerLineJoin.miter
                    self.shape.strokeColor = UIColor.white.cgColor
                    self.shape.fillColor = UIColor(red: 1.0, green: 0.2, blue: 0.2, alpha: 0.2).cgColor
                    
                    
                    if let firstCoord = self.coordArray.first {
                        path.move(to: firstCoord)
                    }
                    for (index, cgPoint) in self.coordArray.enumerated() {
                        //self.drawCircularPoint(points: cgPoint)
                        if index == 0 {
                            continue
                        }
                        path.addLine(to: cgPoint)
                    }
                    path.close()
                    shape.path = path.cgPath
                }
                
                
            }

        }
        //self.bringSubviewToFront(viewDrag)
    }
    
    private func updateCoordinateArray() -> Void {
        for singleCoordinate in self.coordinatePoints {
            if singleCoordinate.contains(",") == true {
            
                let splitCoordinate = singleCoordinate.split(separator: ",")
                
                if splitCoordinate.count == 2 {
                    let xPos = CGFloat(Float(splitCoordinate[0]) ?? 0.0)
                    let yPos = CGFloat(Float(splitCoordinate[1]) ?? 0.0)
                    let cgPoint = CGPoint(x: xPos, y: yPos)
                    
                    self.coordArray.append(cgPoint)
                }
            }
        }
        
        var penultimateIndex: Int?
        if let penultimateCoordinate = self.coordArray.penultimate() {
            penultimateIndex =  self.coordArray.firstIndex { (cgpoint) -> Bool in
                if penultimateCoordinate == cgpoint {
                    return true
                }
                return false
            }
        }
        var lastIndex: Int?
        if let lastCoordinate = self.coordArray.last {
            lastIndex =  self.coordArray.firstIndex { (cgpoint) -> Bool in
                if lastCoordinate == cgpoint {
                    return true
                }
                return false
            }
        }
        if penultimateIndex != nil amp;amp; lastIndex != nil {
            self.coordArray.swapAt(penultimateIndex!, lastIndex!)
        }
    }
  

введите описание изображения здесь
введите описание изображения здесь
»’

Я создаю полигон, используя UIBezierPath и CAShapeLayer. Добавлен жест панорамирования во всех 4 точках, которые являются UIView. Когда я перетаскиваю точки A, B, C, D, ожидаемое поведение заключается в том, что bezierpath и CAShapeLayer обновляются с обновленными точками. И когда пользователь перетаскивает внутреннюю часть фигуры, весь путь обновляется. Но я не могу обновить путь и форму. Кто-нибудь может мне помочь с этим?

Ответ №1:

вы задали имя для слоя

 var shape = CAShapeLayer()
shape.name = "name1"
  

и тогда, вместо обновления, вы можете удалить его, сначала выполнив поиск по имени, а затем добавив