ios - 为图像缩放添加 UIScrollView 会破坏 UIImageView 中的绘图
问题描述
我使用 2 个 UIImageViews 创建了一个绘图画布。有 2 个的原因与橡皮擦功能(在此最小可重现示例中不存在)有关,该功能将白色应用于其中一个,当用户将手指从屏幕上抬起时,它将白色笔划合并到另一个 UIImageView 中。
当我添加一个 UIScrollView 以允许通过捏合和双击手势进行放大和缩小时,它阻止了我绘图。touchesBegan 方法中的 print 语句永远不会执行。关于 UIScrollView 的某些东西干扰了绘图方法。
import UIKit
extension UIView {
var safeAreaBottom: CGFloat {
if #available(iOS 11, *) {
if let window = UIApplication.shared.keyWindowInConnectedScenes {
return window.safeAreaInsets.bottom
}
}
return 0
}
var safeAreaTop: CGFloat {
if #available(iOS 11, *) {
if let window = UIApplication.shared.keyWindowInConnectedScenes {
return window.safeAreaInsets.top
}
}
return 0
}
}
/* Identifies the key window in the app so the current window can be accessed in above 2 methods to get it's bottom and top
safe area insets (navigation toolbar / tabBar).
*/
extension UIApplication {
var keyWindowInConnectedScenes: UIWindow? {
return windows.first(where: { $0.isKeyWindow })
}
}
extension ViewController: UIScrollViewDelegate {
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return finalImage
}
func scrollViewDidZoom(_ scrollView: UIScrollView) {
centerImage()
}
}
class ViewController: UIViewController {
@IBOutlet weak var imageScrollView: UIScrollView!
@IBOutlet weak var finalImage: UIImageView!
@IBOutlet weak var drawImage: UIImageView!
var lastPoint = CGPoint.zero
var color: UIColor = .black
var lineWidth: CGFloat = 10.0
var opacity: CGFloat = 1.0
var swiped = Bool()
var screenBounds = CGRect()
var screenWidth = CGFloat()
var screenHeight = CGFloat()
let drawView = UIView()
var image: UIImage?
override func viewDidLoad() {
super.viewDidLoad()
screenWidth = view.bounds.width
screenHeight = view.bounds.height
screenBounds = CGRect(x: 0, y: 0, width: screenWidth, height: screenHeight)
drawView.alignmentRect(forFrame: screenBounds)
image = UIImage(named: "landscape")
finalImage.image = image
finalImage.image = imageResize(image: finalImage.image!, sizeChange: finalImage.intrinsicContentSize)
finalImage.contentMode = .scaleAspectFit
finalImage.alignmentRect(forFrame: CGRect(origin: .zero, size: image?.size ?? CGSize(width: 0, height: 0)))
drawImage.alignmentRect(forFrame: CGRect(origin: .zero, size: image?.size ?? CGSize(width: 0, height: 0)))
imageScrollView.delegate = self
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
if let image = image {
setMinZoomScaleForImageSize(image.size)
}
}
func imageResize(image: UIImage, sizeChange: CGSize) -> UIImage {
let hasAlpha = true
let scale: CGFloat = 0.0 // Use scale factor of main screen
// Create a Drawing Environment (which will render to a bitmap image, later)
UIGraphicsBeginImageContextWithOptions(sizeChange, !hasAlpha, scale)
image.draw(in: CGRect(origin: .zero, size: sizeChange))
let scaledImage = UIGraphicsGetImageFromCurrentImageContext()
// Clean up the Drawing Environment (created above)
UIGraphicsEndImageContext()
return scaledImage!
}
func drawLine(from fromPoint: CGPoint, to toPoint: CGPoint) {
UIGraphicsBeginImageContext(CGSize(width: screenWidth, height: screenHeight))
guard let context = UIGraphicsGetCurrentContext() else { return }
finalImage.image?.draw(in: screenBounds)
context.move(to: fromPoint)
context.addLine(to: toPoint)
context.setLineCap(.round)
context.setBlendMode(.normal)
context.setLineWidth(lineWidth)
context.setStrokeColor(color.cgColor)
context.strokePath()
finalImage.image = UIGraphicsGetImageFromCurrentImageContext()
finalImage.alpha = opacity
UIGraphicsEndImageContext()
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
print("in touches began!")
guard let touch = touches.first else { return }
swiped = false
lastPoint = touch.location(in: drawView)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let touch = touches.first else { return }
swiped = true
var currentPoint = touch.location(in: drawView)
drawLine(from: lastPoint, to: currentPoint)
lastPoint = currentPoint
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
// draw a single point
if swiped { drawLine(from: lastPoint, to: lastPoint) } else { return }
// Merge drawImageView into finalImageView
UIGraphicsBeginImageContext(finalImage.frame.size)
finalImage.image?.draw(in: screenBounds, blendMode: .normal, alpha: 1.0)
drawImage?.image?.draw(in: screenBounds, blendMode: .normal, alpha: opacity)
finalImage.image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
drawImage.image = nil
}
@IBAction func doubleTapImage(_ sender: UITapGestureRecognizer) {
if imageScrollView.zoomScale == imageScrollView.minimumZoomScale {
imageScrollView.zoom(to: zoomRectangle(scale: imageScrollView.maximumZoomScale, center: sender.location(in: sender.view)), animated: true)
} else {
imageScrollView.setZoomScale(imageScrollView.minimumZoomScale, animated: true)
}
}
// MARK: - Zoom IN / OUT Helper Methods Begin
private func setMinZoomScaleForImageSize(_ imageSize: CGSize) {
let widthScale = view.frame.width / imageSize.width
let heightScale = view.frame.height / imageSize.height
let minScale = min(widthScale, heightScale)
// Scale the image down to fit in the view
imageScrollView.minimumZoomScale = minScale
imageScrollView.zoomScale = minScale
// Set the image frame size after scaling down
let imageWidth = imageSize.width * minScale
let imageHeight = imageSize.height * minScale
let newImageFrame = CGRect(x: 0, y: 0, width: imageWidth, height: imageHeight)
finalImage.frame = newImageFrame
centerImage()
}
private func centerImage() {
let imageViewSize = finalImage.frame.size
let scrollViewSize = view.frame.size
let verticalPadding = imageViewSize.height < scrollViewSize.height ? (scrollViewSize.height - imageViewSize.height) / 2 : 0
let horizontalPadding = imageViewSize.width < scrollViewSize.width ? (scrollViewSize.width - imageViewSize.width) / 2 : 0
imageScrollView.contentInset = UIEdgeInsets(top: verticalPadding, left: horizontalPadding, bottom: verticalPadding, right: horizontalPadding)
}
private func zoomRectangle(scale: CGFloat, center: CGPoint) -> CGRect {
var zoomRect = CGRect.zero
zoomRect.size.height = finalImage.frame.size.height / scale
zoomRect.size.width = finalImage.frame.size.width / scale
zoomRect.origin.x = center.x - (center.x * imageScrollView.zoomScale)
zoomRect.origin.y = center.y - (center.y * imageScrollView.zoomScale)
return zoomRect
}
}
解决方案
推荐阅读
- c# - 转换为双 5.55111512312578E-17
- libreoffice - 在 LibreOffice Calc 中查找以匹配搜索条件的部分字符串
- apache-kafka - 在 kafka log.dir 配置中添加多个目录并为某些分区创建软链接。有什么不同?
- python - Python-对数字进行分类
- python - 给定公钥,PGP 在 Python 中加密输入文件
- c# - 如何处理可能不存在的 dll 依赖项?
- r - How to find the joint cumulative distribution function from a 2-D copula in R?
- matlab - 相机视角(垂直和水平)
- spring-boot - 在 LogBack 中为 Spring Boot 应用程序检测云平台
- android-studio - Android Studio 3.3 在新错误中损坏了所有项目文件