在 Swift / IOS 中将 shapeLayer 添加到视图层时 Draw 应用程序滞后
Draw app is Lagging when adding shapeLayer into views layer in Swift / IOS
我正在创建一个绘图应用程序。这个应用程序允许用户在视图上绘图。我在下面给出的代码中命名该视图绘图视图。为了创建这个应用程序,我使用了 BeizerPath 和 ShapeLayer,每当用户触摸屏幕时 UIBeizerPath 和 CAShapeLayer 初始化。这个应用程序的问题是在一些绘图视图变得滞后之后。我不知道发生了什么。有没有更好的方法来优化这个应用程序?
CanvasViewController: UIViewController {
// MARK: Properties
@IBOutlet weak var verticalScrollView: UIScrollView!
var lastPoint:CGPoint? // var mutablePath:CGMutablePath?
var drawLine:UIBezierPath?
var shapeLayer:CAShapeLayer?
let dropDown = DropDown()
var shape:CAShapeLayer?
let listOfDropDownMenu:[String] = ["Create New Canvas","Save","Change Color"]
var presenter: CanvasModuleInterface?
// MARK: IBOutlets
@IBOutlet weak var drawingView: UIView!
@IBOutlet weak var showColorViewControllerDropDownButton: UIBarButtonItem!
// MARK: VC's Life cycle
override func viewDidLoad() {
super.viewDidLoad()
self.setup()
self.verticalScrollView.isUserInteractionEnabled = false
}
// MARK: IBActions
// MARK: Other Functions
@IBAction func ShowColorViewControllerAction(_ sender: Any) {
self.dropDown.anchorView = self.showColorViewControllerDropDownButton
self.dropDown.dataSource = self.listOfDropDownMenu
self.dropDown.selectionAction = { [unowned self] (index: Int, item: String) in
switch index{
case 0:
self.createNewView()
case 1:
self.saveTheCanvas()
case 2:
self.presentToColorViewController()
//self.presentColorController()
default:
print("out of order !!!")
}
}
self.dropDown.show()
}
private func createNewView(){
//Mark: - create new canvas
self.drawingView.layer.sublayers!.forEach { (layers) in
layers.removeFromSuperlayer()
}
}
private func presentToColorViewController(){
// Mark : - naviagate to color view controller.
}
private func saveTheCanvas(){
// Mark: - save the drawing
}
private func setup() {
// all setup should be done here
}
private func presentColorController(){
let colorSelectionController = EFColorSelectionViewController()
let colorNavigationController = UINavigationController(rootViewController: colorSelectionController)
colorNavigationController.navigationBar.backgroundColor = UIColor.white
colorNavigationController.navigationBar.isTranslucent = false
colorNavigationController.modalPresentationStyle = UIModalPresentationStyle.popover
colorSelectionController.delegate = self
colorSelectionController.color = self.view.backgroundColor ?? UIColor.white
if UIUserInterfaceSizeClass.compact == self.traitCollection.horizontalSizeClass {
let doneButton: UIBarButtonItem = UIBarButtonItem(
title: NSLocalizedString("Done", comment: ""),
style: UIBarButtonItem.Style.done,
target: self,
action: #selector(dismissViewController)
)
colorSelectionController.navigationItem.rightBarButtonItem = doneButton
}
self.present(colorNavigationController, animated: true, completion: nil)
}
@objc func dismissViewController(){
//##ask confusion.....
self.dismiss(animated: true, completion: nil)
}
}
// MARK: CanvasViewInterface extension CanvasViewController: CanvasViewInterface {
} extension CanvasViewController: EFColorSelectionViewControllerDelegate{
func colorViewController(_ colorViewCntroller: EFColorSelectionViewController, didChangeColor color: UIColor) {
} } extension CanvasViewController{
//Mark: - this extension contains function for drawing the circle.
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
print("touches begin")
self.drawLine = UIBezierPath()
self.shapeLayer = CAShapeLayer()
// self.mutablePath = CGMutablePath()
if let touchesPoint = touches.first{
self.lastPoint = touchesPoint.location(in: self.drawingView)
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
// self.drawingView.layer.sublayers!.forEach { (layer) in // print(layer) // }
// print(self.drawingView.layer)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?){ // print("\(self.drawingView)") // print("\(self.drawingView.layer.sublayers)")
var nextPoint:CGPoint?
if let touchesPoint = touches.first{
nextPoint = touchesPoint.location(in: self.drawingView)
guard let lastLinePoint = self.lastPoint , let nextLinePoint = nextPoint else{return}
self.drawLineInDrawingView(from: lastLinePoint, to: nextLinePoint)
}
if let newPoint = nextPoint{
self.lastPoint = newPoint
}
}
func drawLineInDrawingView(from:CGPoint,to:CGPoint){
drawLine!.move(to: CGPoint(x: from.x, y: from.y))
drawLine!.addLine(to: CGPoint(x: to.x, y: to.y))
shapeLayer!.path = drawLine!.cgPath
shapeLayer!.strokeColor = UIColor.black.cgColor
shapeLayer!.lineCap = .round
shapeLayer!.lineWidth = 100
self.drawingView.layer.addSublayer(shapeLayer!) // print(self.drawingView.layer.sublayers)
}
}
不知道 CanvasViewController
你在用什么,不能完全正确地回答你的问题,但我会回答,假设它的工作方式类似于 iOS 中的任何常规 UIView。
有几点我可以指出来提高性能:
首先,不要将相同的 ShapeLayer
在 drawLineInDrawingView(from:CGPoint,to:CGPoint)
中一遍又一遍地添加到绘图视图中,而是只在 touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?)
中添加一次并存储对它。
其次,您的 drawLineInDrawingView(from:CGPoint,to:CGPoint)
应该如下所示:
func drawLineInDrawingView(from:CGPoint,to:CGPoint){
CATransaction.begin()
CATransaction.setDisableActions(true)
drawLine!.move(to: CGPoint(x: from.x, y: from.y))
drawLine!.addLine(to: CGPoint(x: to.x, y: to.y))
shapeLayer!.path = drawLine!.cgPath
shapeLayer!.strokeColor = UIColor.black.cgColor
shapeLayer!.lineCap = .round
shapeLayer!.lineWidth = 100
shapeLayer!.setNeedsDisplay()
CATransaction.commit()
}
总而言之:在 touchesBegan() 之后,您添加了 shapeLayer 并存储了对它的引用。在 touchesMoved 中,您调用 drawLineInDrawingsFunction。
您的 drawLineInDrawingsFunction,仅使用 shapeLayer.setNeedsDisplay()
.
更新您的 Shapelayer
将你的转换放在里面
CATransaction.begin()
CATransaction.setDisableActions(true)
/**Your transformation here**/
CATransaction.commit()
只是为了阻止您的视图自动动画更改,而是立即显示它们。
希望对您有所帮助。
我正在创建一个绘图应用程序。这个应用程序允许用户在视图上绘图。我在下面给出的代码中命名该视图绘图视图。为了创建这个应用程序,我使用了 BeizerPath 和 ShapeLayer,每当用户触摸屏幕时 UIBeizerPath 和 CAShapeLayer 初始化。这个应用程序的问题是在一些绘图视图变得滞后之后。我不知道发生了什么。有没有更好的方法来优化这个应用程序?
CanvasViewController: UIViewController {
// MARK: Properties
@IBOutlet weak var verticalScrollView: UIScrollView!
var lastPoint:CGPoint? // var mutablePath:CGMutablePath?
var drawLine:UIBezierPath?
var shapeLayer:CAShapeLayer?
let dropDown = DropDown()
var shape:CAShapeLayer?
let listOfDropDownMenu:[String] = ["Create New Canvas","Save","Change Color"]
var presenter: CanvasModuleInterface?
// MARK: IBOutlets
@IBOutlet weak var drawingView: UIView!
@IBOutlet weak var showColorViewControllerDropDownButton: UIBarButtonItem!
// MARK: VC's Life cycle
override func viewDidLoad() {
super.viewDidLoad()
self.setup()
self.verticalScrollView.isUserInteractionEnabled = false
}
// MARK: IBActions
// MARK: Other Functions
@IBAction func ShowColorViewControllerAction(_ sender: Any) {
self.dropDown.anchorView = self.showColorViewControllerDropDownButton
self.dropDown.dataSource = self.listOfDropDownMenu
self.dropDown.selectionAction = { [unowned self] (index: Int, item: String) in
switch index{
case 0:
self.createNewView()
case 1:
self.saveTheCanvas()
case 2:
self.presentToColorViewController()
//self.presentColorController()
default:
print("out of order !!!")
}
}
self.dropDown.show()
}
private func createNewView(){
//Mark: - create new canvas
self.drawingView.layer.sublayers!.forEach { (layers) in
layers.removeFromSuperlayer()
}
}
private func presentToColorViewController(){
// Mark : - naviagate to color view controller.
}
private func saveTheCanvas(){
// Mark: - save the drawing
}
private func setup() {
// all setup should be done here
}
private func presentColorController(){
let colorSelectionController = EFColorSelectionViewController()
let colorNavigationController = UINavigationController(rootViewController: colorSelectionController)
colorNavigationController.navigationBar.backgroundColor = UIColor.white
colorNavigationController.navigationBar.isTranslucent = false
colorNavigationController.modalPresentationStyle = UIModalPresentationStyle.popover
colorSelectionController.delegate = self
colorSelectionController.color = self.view.backgroundColor ?? UIColor.white
if UIUserInterfaceSizeClass.compact == self.traitCollection.horizontalSizeClass {
let doneButton: UIBarButtonItem = UIBarButtonItem(
title: NSLocalizedString("Done", comment: ""),
style: UIBarButtonItem.Style.done,
target: self,
action: #selector(dismissViewController)
)
colorSelectionController.navigationItem.rightBarButtonItem = doneButton
}
self.present(colorNavigationController, animated: true, completion: nil)
}
@objc func dismissViewController(){
//##ask confusion.....
self.dismiss(animated: true, completion: nil)
}
}
// MARK: CanvasViewInterface extension CanvasViewController: CanvasViewInterface {
} extension CanvasViewController: EFColorSelectionViewControllerDelegate{
func colorViewController(_ colorViewCntroller: EFColorSelectionViewController, didChangeColor color: UIColor) {
} } extension CanvasViewController{
//Mark: - this extension contains function for drawing the circle.
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
print("touches begin")
self.drawLine = UIBezierPath()
self.shapeLayer = CAShapeLayer()
// self.mutablePath = CGMutablePath()
if let touchesPoint = touches.first{
self.lastPoint = touchesPoint.location(in: self.drawingView)
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
// self.drawingView.layer.sublayers!.forEach { (layer) in // print(layer) // }
// print(self.drawingView.layer)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?){ // print("\(self.drawingView)") // print("\(self.drawingView.layer.sublayers)")
var nextPoint:CGPoint?
if let touchesPoint = touches.first{
nextPoint = touchesPoint.location(in: self.drawingView)
guard let lastLinePoint = self.lastPoint , let nextLinePoint = nextPoint else{return}
self.drawLineInDrawingView(from: lastLinePoint, to: nextLinePoint)
}
if let newPoint = nextPoint{
self.lastPoint = newPoint
}
}
func drawLineInDrawingView(from:CGPoint,to:CGPoint){
drawLine!.move(to: CGPoint(x: from.x, y: from.y))
drawLine!.addLine(to: CGPoint(x: to.x, y: to.y))
shapeLayer!.path = drawLine!.cgPath
shapeLayer!.strokeColor = UIColor.black.cgColor
shapeLayer!.lineCap = .round
shapeLayer!.lineWidth = 100
self.drawingView.layer.addSublayer(shapeLayer!) // print(self.drawingView.layer.sublayers)
}
}
不知道 CanvasViewController
你在用什么,不能完全正确地回答你的问题,但我会回答,假设它的工作方式类似于 iOS 中的任何常规 UIView。
有几点我可以指出来提高性能:
首先,不要将相同的 ShapeLayer
在 drawLineInDrawingView(from:CGPoint,to:CGPoint)
中一遍又一遍地添加到绘图视图中,而是只在 touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?)
中添加一次并存储对它。
其次,您的 drawLineInDrawingView(from:CGPoint,to:CGPoint)
应该如下所示:
func drawLineInDrawingView(from:CGPoint,to:CGPoint){
CATransaction.begin()
CATransaction.setDisableActions(true)
drawLine!.move(to: CGPoint(x: from.x, y: from.y))
drawLine!.addLine(to: CGPoint(x: to.x, y: to.y))
shapeLayer!.path = drawLine!.cgPath
shapeLayer!.strokeColor = UIColor.black.cgColor
shapeLayer!.lineCap = .round
shapeLayer!.lineWidth = 100
shapeLayer!.setNeedsDisplay()
CATransaction.commit()
}
总而言之:在 touchesBegan() 之后,您添加了 shapeLayer 并存储了对它的引用。在 touchesMoved 中,您调用 drawLineInDrawingsFunction。
您的 drawLineInDrawingsFunction,仅使用 shapeLayer.setNeedsDisplay()
.
将你的转换放在里面
CATransaction.begin()
CATransaction.setDisableActions(true)
/**Your transformation here**/
CATransaction.commit()
只是为了阻止您的视图自动动画更改,而是立即显示它们。
希望对您有所帮助。