[英]How can i draw lines from touches in single CAShapeLayer to be able to select and move UIBezierPaths?
我正在嘗試用觸摸畫線,然后能夠移動它。 我沒有使用帶有 draw(_ rect: CGRect) 的 UIContext 方法進行繪圖,因為我無法獲得筆畫的大小及其一些屬性,所以我使用 CAShapeLayer 來使用如下觸摸方法進行繪圖:
let shapeLayer: CAShapeLayer = {
let layer = CAShapeLayer()
layer.lineWidth = 1
layer.strokeColor = UIColor.black.cgColor
layer.fillColor = UIColor.clear.cgColor
layer.lineCap = .round
layer.lineJoin = .round
layer.lineDashPattern = [10, 10]
layer.name = "ShapeLayer"
return layer
}()
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let shapeLayer = CAShapeLayer()
shapeLayer.lineWidth = 1
shapeLayer.strokeColor = UIColor.black.cgColor
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.lineCap = .round
shapeLayer.lineJoin = .round
shapeLayer.lineDashPattern = [10, 10]
shapeLayer.name = "ShapeLayer"
self.canvas.layer.addSublayer(shapeLayer)
path = MyBezierPath()
if let location = touches.first?.location(in: self.canvas) { previousTouchPoint = location }
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let touch = touches.first?.location(in: self.canvas) else { return }
if let location = touches.first?.location(in: self.canvas) {
path.move(to: location)
path.addLine(to: previousTouchPoint)
previousTouchPoint = location
if canvas.layer.sublayers != nil && canvas.layer.sublayers?.last?.name == "ShapeLayer" {
guard let layer = canvas.layer.sublayers?.last as? CAShapeLayer else { return }
print("Here \(layer.path?.boundingBoxOfPath)")
layer.path = path.cgPath
}
}
}
我試圖將所有 UIBezierpath 添加到單個 CAShapeLayer 以便我可以 select 特定路徑並移動它。 但是在這種方法中,它為每一行創建新的 CAShapeLayer,所以我嘗試定義全局 CAShapeLayer 變量並為所有行附加 UIBezierPath 並將其添加到全局 CAShapeLayer 變量,但它非常緩慢且滯后。 有什么辦法我可以只用一個 CAShapeLayer 繪制然后能夠改變它的 BezierPath 的位置?
這是將多個“線段”添加到單個UIBezierPath
的簡單示例,然后能夠拖動/移動該路徑。
在UIView
子類中,我們:
UIBezierPath
我們稱之為thePath
CAShapeLayer
-- shapeLayer
thePath.move(to: point)
thePath.addLine(to: point)
和shapeLayer.path = thePath.cgPath
在啟動時,它看起來像這樣:
我們觸摸並拖動以添加到路徑:
更多的觸摸和拖動以添加更多“段”:
現在我們切換到“移動”並向下和向右拖動:
切換回“Draw”並添加更多片段:
切換回“移動”並向上和向左拖動:
示例 controller
class DrawMoveLayerTestVC: UIViewController {
let testView = DrawMoveLayerView()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBackground
testView.backgroundColor = UIColor(white: 0.95, alpha: 1.0)
testView.translatesAutoresizingMaskIntoConstraints = false
// segmented control to switch between drawing / moving
let segControl = UISegmentedControl(items: ["Draw", "Move"])
segControl.translatesAutoresizingMaskIntoConstraints = false
segControl.selectedSegmentIndex = 0
segControl.addTarget(self, action: #selector(segChanged(_:)), for: .valueChanged)
view.addSubview(testView)
view.addSubview(segControl)
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
// put segmented control at bottom
segControl.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
segControl.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
segControl.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: -20.0),
// constrain test view to all top/leading/trailing with 20-points "padding"
testView.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0),
testView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
testView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
// bottom to segmented control top with 20-points "padding"
testView.bottomAnchor.constraint(equalTo: segControl.topAnchor, constant: -20.0),
])
}
@objc func segChanged(_ sender: UISegmentedControl) {
// set test view to "drawing" or "moving"
testView.isDrawing = sender.selectedSegmentIndex == 0
}
}
示例視圖子類
class DrawMoveLayerView: UIView {
public var isDrawing: Bool = true
private let shapeLayer = CAShapeLayer()
private let thePath = UIBezierPath()
private var startPoint: CGPoint = .zero
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
private func commonInit() {
shapeLayer.lineWidth = 1
shapeLayer.strokeColor = UIColor.black.cgColor
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.lineCap = .round
shapeLayer.lineJoin = .round
shapeLayer.lineDashPattern = [5, 10]
shapeLayer.name = "ShapeLayer"
layer.addSublayer(shapeLayer)
self.clipsToBounds = true
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let t = touches.first else { return }
let point = t.location(in: self)
if isDrawing {
thePath.move(to: point)
} else {
self.startPoint = point
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let t = touches.first else { return }
let point = t.location(in: self)
if isDrawing {
thePath.addLine(to: point)
} else {
// move the path by the distance the touch moved
let tr = CGAffineTransform(translationX: point.x - startPoint.x, y: point.y - startPoint.y)
thePath.apply(tr)
startPoint = point
}
// update the path of the shape layer
shapeLayer.path = thePath.cgPath
}
}
在做了一些研究后,我發現不可能在單個 CAShapeLayer 中繪制多條線,您可以繪制單條線但不能繪制多條線。 您可以通過向UIBezierPath
添加新線來繪制多條線,但它會滯后很多。
對於繪制多條線,主要有兩種已知方法:
CGContext
CAShapeLayer
。CAShapeLayer 方法更容易,並且對性能和新手都有好處。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.