Если вы хотите что-то сделать, когда закончили выделять часть изображения, например, внедрите touchesEnded
.
Давайте представим, например, что вы хотите показать прямоугольник предполагаемой области при перетаскивании и сделать снимок изображения выбранной части, когда вы закончите перетаскивание. Затем вы можете сделать что-то вроде:
@IBOutlet weak var imageView: UIImageView!
var startPoint: CGPoint?
let rectShapeLayer: CAShapeLayer = {
let shapeLayer = CAShapeLayer()
shapeLayer.strokeColor = UIColor.black.cgColor
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.lineWidth = 3
return shapeLayer
}()
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
startPoint = nil
guard let touch = touches.first else { return }
startPoint = touch.location(in: imageView)
// you might want to initialize whatever you need to begin showing selected rectangle below, e.g.
rectShapeLayer.path = nil
imageView.layer.addSublayer(rectShapeLayer)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let touch = touches.first, let startPoint = startPoint else { return }
let currentPoint: CGPoint
if let predicted = event?.predictedTouches(for: touch), let lastPoint = predicted.last {
currentPoint = lastPoint.location(in: imageView)
} else {
currentPoint = touch.location(in: imageView)
}
let frame = rect(from: startPoint, to: currentPoint)
// you might do something with `frame`, e.g. show bounding box
rectShapeLayer.path = UIBezierPath(rect: frame).cgPath
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let touch = touches.first, let startPoint = startPoint else { return }
let currentPoint = touch.location(in: imageView)
let frame = rect(from: startPoint, to: currentPoint)
// you might do something with `frame`, e.g. remove bounding box but take snapshot of selected `CGRect`
rectShapeLayer.removeFromSuperlayer()
let image = imageView.snapshot(rect: frame, afterScreenUpdates: true)
// do something with this `image`
}
private func rect(from: CGPoint, to: CGPoint) -> CGRect {
return CGRect(x: min(from.x, to.x),
y: min(from.y, to.y),
width: abs(to.x - from.x),
height: abs(to.y - from.y))
}
Где у вас есть это UIView
расширение для создания снимка:
extension UIView {
/// Create image snapshot of view.
///
/// - Parameters:
/// - rect: The coordinates (in the view's own coordinate space) to be captured. If omitted, the entire `bounds` will be captured.
/// - afterScreenUpdates: A Boolean value that indicates whether the snapshot should be rendered after recent changes have been incorporated. Specify the value false if you want to render a snapshot in the view hierarchy’s current state, which might not include recent changes.
/// - Returns: The `UIImage` snapshot.
func snapshot(rect: CGRect? = nil, afterScreenUpdates: Bool = true) -> UIImage {
return UIGraphicsImageRenderer(bounds: rect ?? bounds).image { _ in
drawHierarchy(in: bounds, afterScreenUpdates: afterScreenUpdates)
}
}
}
Теперь, если вы хотите сделать что-то кроме захвата снимка изображения, тогда, хорошо, делайте что хотите. Но это иллюстрирует основную идею.
Пара незначительных вещей в моем примере выше:
Обратите внимание, что я ограничиваю свои ивары теми вещами, которые мне абсолютно необходимы. Например. текущий touch
, вероятно, должен быть локальной переменной, а не иваром. Мы всегда должны ограничивать наши переменные максимально узким диапазоном, чтобы избежать непредвиденных последствий и т. Д.
Я добавил небольшое уточнение к вашему touchesMoved
, чтобы использовать прогнозирующие штрихи. В этом нет необходимости, но это может помочь свести к минимуму любое кажущееся отставание при перетаскивании пальца.
Я не совсем уверен, почему вы позвонили setNeedsDisplay
. Это кажется ненужным, если не было чего-то еще, что вы намеревались там.
Я не уверен, какой режим содержания вы использовали для просмотра изображений. Например, если вы использовали «Подгонка масштаба» и хотели сделать снимок этого, вы можете выбрать другой алгоритм моментального снимка, например, как описано в https://stackoverflow.com/a/54191120/1271826.