Swift中如何避免绘制时出现多条重叠线条?
Hey there! Let's work through those three drawing problems you're dealing with—slow-drawn lines being too dark, weak overlap darkening, and inconsistent line breaks between fast/slow draws. Here's how to refactor your code to fix everything:
1. Why Slow-Drawn Lines Are Too Dark (And How to Fix It)
The root issue is that your current code redraws a new line segment to tempImageView every time touchesMoved fires. With opacity = 0.5, slow draws mean dozens of overlapping segments that stack up to make the line darker. Instead, we'll accumulate the entire drawing path first, then render it once per update to avoid repeated layering.
2. Making Overlap Darkening More Pronounced
Using the .multiply blend mode instead of .normal when merging strokes into the main image will make overlapping areas darken more noticeably—this mimics how real ink builds up on paper for a more natural effect.
3. Eliminating Line Breaks for Consistent Draws
Adding lineJoin = .round ensures smooth connections between path segments, and rendering the full accumulated path instead of individual segments eliminates breaks from fast movement.
Refactored Code
First, add these properties to your view controller:
private var currentPath: CGMutablePath? private var currentStrokeColor: UIColor? private var currentLineWidth: CGFloat = 0.0 private var currentOpacity: CGFloat = 1.0 private var swiped = false private var lastPoint = CGPoint.zero // Keep your existing red/green/blue/opacity/brushWidth properties
Then update your touch handling methods:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { guard let touch = touches.first else { return } swiped = false let startPoint = touch.location(in: view) // Initialize a new path for the current stroke currentPath = CGMutablePath() currentPath?.move(to: startPoint) currentStrokeColor = UIColor(red: red, green: green, blue: blue, alpha: opacity) currentLineWidth = brushWidth currentOpacity = opacity lastPoint = startPoint } override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) { guard let touch = touches.first, let path = currentPath else { return } swiped = true let currentPoint = touch.location(in: view) path.addLine(to: currentPoint) lastPoint = currentPoint // Redraw the temp image with the full accumulated path updateTempImageView() } override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) { finishDrawing() } override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) { finishDrawing() }
Add these helper methods:
private func updateTempImageView() { UIGraphicsBeginImageContext(view.frame.size) guard let context = UIGraphicsGetCurrentContext(), let path = currentPath, let strokeColor = currentStrokeColor else { UIGraphicsEndImageContext() return } // Draw existing main strokes so you can see them while drawing mainImageView.image?.draw(in: view.bounds) // Configure drawing settings for smooth, consistent lines context.addPath(path) context.setLineCap(.round) context.setLineJoin(.round) // Smooths connections between segments context.setBlendMode(.normal) context.setLineWidth(currentLineWidth) context.setStrokeColor(strokeColor.cgColor) // Stroke the entire path once (no more stacking!) context.strokePath() tempImageView.image = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() } private func finishDrawing() { // Handle single taps (draw a dot) if !swiped { currentPath?.addLine(to: lastPoint) updateTempImageView() } // Merge temp stroke into main image with stronger overlap darkening UIGraphicsBeginImageContext(mainImageView.frame.size) mainImageView.image?.draw(in: view.bounds, blendMode: .normal, alpha: 1.0) tempImageView.image?.draw(in: view.bounds, blendMode: .multiply, alpha: currentOpacity) mainImageView.image = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() // Reset for next stroke tempImageView.image = nil currentPath = nil }
Key Changes Explained
- Path Accumulation: We build a single path for each stroke instead of drawing individual segments, so slow draws don't stack up dark layers.
- Smooth Line Joins:
setLineJoin(.round)ensures fast-moving segments connect seamlessly, eliminating breaks. - Stronger Overlap:
.multiplyblend mode makes overlapping areas darken significantly more than.normal. - Consistent Rendering: The entire stroke is rendered once per update, so fast and slow draws look identical in consistency and brightness.
Give these changes a test run—you should see all your issues resolved!
内容的提问来源于stack exchange,提问作者PorkyTheChop

