Линия UIBezierPath исчезает при рисовании другой

#swift #uibezierpath

#swift #uibezierpath

Вопрос:

Я пытаюсь нарисовать несколько с помощью UIBezierPath, но всякий раз, когда я пытаюсь нарисовать 2-ю, первая исчезает. Пытался создать несколько BezierPath и поместить их в массив, но я получил эту ошибку, когда она столкнулась с case:ended

test[2687:238999] [Unknown process name] CGPathCloseSubpath: no current point.

Это мой код

 
 private lazy var lineShape: CAShapeLayer = {
        let lineShape = CAShapeLayer()
        lineShape.strokeColor = UIColor.blue.cgColor
        lineShape.lineWidth = 2.0

        return lineShape
    }()
    
 var bezierPathArr:NSMutableArray = []
 private var panGestureStartPoint: CGPoint = .zero
 private lazy var panRecognizer: UIPanGestureRecognizer = {
        return UIPanGestureRecognizer(target: self, action: #selector(panGestureCalled(_:)))
    }()

 @objc func panGestureCalled(_: UIPanGestureRecognizer) {
        let linePath = UIBezierPath()
        let currentPanPoint = panRecognizer.location(in: self.view)
        switch panRecognizer.state {
        case .began:
            panGestureStartPoint = currentPanPoint
            self.view.layer.addSublayer(lineShape)
            bezierPathArr.add(linePath)

        case .changed:
            linePath.move(to: panGestureStartPoint)
            linePath.addLine(to: currentPanPoint)
            lineShape.path = linePath.cgPath

        case .ended:
            let finalPath:UIBezierPath = bezierPathArr.lastObject as! UIBezierPath
            finalPath.close()
    
        default: break
        }
    }


  

Комментарии:

1. С помощью представленного вами кода вы создаете новую UIBezierPath каждый раз, когда запускается распознаватель жестов. Вы захотите сохранить свой linePath как экземпляр в своем классе, а затем в .begin состоянии повторно инициализировать путь и .move(to:) точку.

2.Я попробовал то, что вы предложили, и она все еще исчезает, когда начинает рисоваться вторая строка. Теперь она рисует другую линию всякий раз, когда я перемещаю мышь, вместо того, чтобы быть растянутой. Я создаю экземпляр var linePath:UIBezierPath? и инициализирую в .begin linePath = UIBezierPath()

Ответ №1:

Из-за lazy создания вашего CAShapeLayer , всякий раз, когда вы добавляете слой в свой вид, вы используете одну и ту же ссылку на объект. Это наряду с установкой пути по этой ссылке даст вам поведение, с которым вы сталкиваетесь.

Для достижения ожидаемого поведения вам необходимо создать и сохранить новый CAShapeLayer для каждого из ваших завершенных жестов. Вот рабочий пример:

 class ViewController: UIViewController {
    
    private lazy var panRecognizer: UIPanGestureRecognizer = {
        return UIPanGestureRecognizer(target: self, action: #selector(panGestureCalled(_:)))
    }()
    
    /// The path that is being drawn (resets on .began, closes on .ended)
    private var currentPath: UIBezierPath = .init()
    /// All of the layers added to the view
    private var shapes: [CAShapeLayer] = []
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.addGestureRecognizer(panRecognizer)
    }

    @objc private func panGestureCalled(_ sender: UIPanGestureRecognizer) {
        let point = sender.location(in: self.view)
        switch sender.state {
        case .began:
            // Reset the path
            currentPath = .init()
            // Set the starting point
            currentPath.move(to: point)
            // Creates a new layer when gesture starts.
            let layer = newShapeLayer()
            // Save the layer with all shapes.
            shapes.append(layer)
            // Add the layer to the view
            view.layer.addSublayer(layer)
        case .changed:
            // Update the current path to the new point
            currentPath.addLine(to: point)
        case .ended:
            // Close/Finish the path
            currentPath.close()
        default:
            break
        }
        
        // Update the most-current shape with the path being drawn.
        shapes.last?.path = currentPath.cgPath
    }
    
    /// Creates a new `CAShapeLayer`
    private func newShapeLayer() -> CAShapeLayer {
        let layer = CAShapeLayer()
        layer.frame = view.bounds
        layer.strokeColor = UIColor.blue.cgColor
        layer.lineWidth = 2.0
        return layer
    }
}