Skip to content

Instantly share code, notes, and snippets.

@mryssng
Last active May 3, 2018 15:12
Show Gist options
  • Save mryssng/2afbc9bd2efe4706142e89e8aef6564f to your computer and use it in GitHub Desktop.
Save mryssng/2afbc9bd2efe4706142e89e8aef6564f to your computer and use it in GitHub Desktop.
Gesture Image Zoom View Controller without UIScrollView
//
// SelectedImageViewController.swift
//
// Created by Ytse Jam on 2017/10/25.
// Copyright © 2017 Ytse Jam. Licensed under MIT.
//
import UIKit
class SelectedImageViewController: UIViewController, UIGestureRecognizerDelegate, UIScrollViewDelegate{
@IBOutlet weak var baseView: UIView!
@IBOutlet var imageView: UIImageView!
@IBOutlet weak var drawView: DrawRectangleView!
@IBOutlet weak var analysisButton: RoundedCornersButton!
var params = SelectionParameters()
var image: UIImage? = nil
private var croppedImage: UIImage? = nil
var currentTransform: CGAffineTransform? = nil
var pinchStartImageCenter: CGPoint = CGPoint(x: 0, y: 0)
let maxScale: CGFloat = 4.0
let minScale: CGFloat = 1.0
var currentScale: CGFloat = 1.0
var pichCenter: CGPoint = CGPoint(x: 0, y: 0)
var width:CGFloat = 0
var height:CGFloat = 0
var screenWidth:CGFloat = 0
var screenHeight:CGFloat = 0
override func viewDidLoad() {
super.viewDidLoad()
// Set an image to UIImageView
imageView.image = self.image
self.imageView.isUserInteractionEnabled = true
// Get Screen Size
screenWidth = self.view.bounds.width
screenHeight = self.view.bounds.height
// Get Image Size
self.width = (self.image?.size.width)!
self.height = (self.image?.size.height)!
// Fit Image Width to Screen Width
currentScale = self.screenWidth / self.width
let rect: CGRect = CGRect(x: 0, y: 0, width: self.width * self.currentScale, height: self.height * self.currentScale)
// Set rect to ImageView.frame
self.imageView.frame = rect;
// Move Image Center to Screen Center
self.imageView.center = CGPoint(x: self.screenWidth/2, y: self.screenHeight/2)
// Set Pan Gesture
let panGesture = UIPanGestureRecognizer(target: self, action: #selector(self.panAction))
panGesture.delegate = self
panGesture.minimumNumberOfTouches = 1
panGesture.maximumNumberOfTouches = 2
self.imageView.addGestureRecognizer(panGesture)
// Set Pinch Gesture
let pinchGetsture = UIPinchGestureRecognizer(target: self, action: #selector(self.pinchAction))
pinchGetsture.delegate = self
self.imageView.addGestureRecognizer(pinchGetsture)
// Set Double Tap Gesture
let doubleTapGesture = UITapGestureRecognizer(target: self, action:#selector(self.doubleTapAction))
doubleTapGesture.numberOfTapsRequired = 2
self.imageView.addGestureRecognizer(doubleTapGesture)
// Init DravRectangleView
self.drawView.isOpaque = false
self.drawView.imageWidth = (self.image?.size.width)!
self.drawView.imageHeight = (self.image?.size.height)!
// Set Analysis Button Title
analysisButton.setTitle(NSLocalizedString("Analysis_Button", comment: ""), for:UIControlState.normal)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
@objc func panAction(gesture: UIPanGestureRecognizer) {
// Store current transfrom of UIImageView
let transform = self.imageView.transform
// Initialize imageView.transform
self.imageView.transform = CGAffineTransform.identity
// Move UIImageView
let point: CGPoint = gesture.translation(in: self.imageView)
let movedPoint = CGPoint(x: self.imageView.center.x + point.x,
y: self.imageView.center.y + point.y)
self.imageView.center = movedPoint
// Revert imageView.transform
self.imageView.transform = transform
// Reset translation
gesture.setTranslation(CGPoint.zero, in: self.imageView)
}
@objc func pinchAction(gesture: UIPinchGestureRecognizer) {
if gesture.state == UIGestureRecognizerState.began { // Begin pinch
// Store current transfrom of UIImageView
self.currentTransform = imageView.transform
// Store initial loaction of pinch action
self.pinchStartImageCenter = imageView.center
let touchPoint1 = gesture.location(ofTouch: 0, in: imageView)
let touchPoint2 = gesture.location(ofTouch: 1, in: imageView)
// Get mid point of two touch
self.pichCenter = CGPoint(x: (touchPoint1.x + touchPoint2.x) / 2, y: (touchPoint1.y + touchPoint2.y) / 2)
} else if gesture.state == UIGestureRecognizerState.changed { // Pinching in operating
// Store scale
let scale = gesture.scale
// Calculate center of pinch location as new UIImageView center
let newCenter = CGPoint(
x: self.pinchStartImageCenter.x - ((self.pichCenter.x - self.pinchStartImageCenter.x) * scale - (self.pichCenter.x - self.pinchStartImageCenter.x)),
y: self.pinchStartImageCenter.y - ((self.pichCenter.y - self.pinchStartImageCenter.y) * scale - (self.pichCenter.y - self.pinchStartImageCenter.y)))
self.imageView.center = newCenter
self.imageView.transform = currentTransform!.concatenating(CGAffineTransform(scaleX: scale, y: scale))
// Update recrangle
let currentScale = sqrt(abs(self.imageView.transform.a * self.imageView.transform.d - self.imageView.transform.b * self.imageView.transform.c))
self.setRectangleScale(scale: currentScale)
} else if gesture.state == UIGestureRecognizerState.ended { // End pinch
// Get current scale
let currentScale = sqrt(abs(self.imageView.transform.a * self.imageView.transform.d - self.imageView.transform.b * self.imageView.transform.c))
var tmpScale: CGFloat = 1.0
var scaleUpdated = false
if currentScale <= self.minScale { // Under lower scale limit
tmpScale = self.minScale
scaleUpdated = true
UIView.animate(withDuration: 0.2, delay: 0.0, options: UIViewAnimationOptions.curveEaseOut, animations: {() -> Void in
self.imageView.center = CGPoint(x: self.imageView.frame.size.width / 2, y: self.imageView.frame.size.height / 2)
self.imageView.transform = CGAffineTransform(scaleX: self.minScale, y: self.minScale)
}, completion: {(finished: Bool) -> Void in
})
} else if self.maxScale <= currentScale { // Upper higher scale limit
tmpScale = self.maxScale
scaleUpdated = true
UIView.animate(withDuration: 0.2, delay: 0.0, options: UIViewAnimationOptions.curveEaseOut, animations: {() -> Void in
self.imageView.center = CGPoint(x: self.baseView.frame.size.width / 2, y: self.baseView.frame.size.height / 2)
self.imageView.transform = CGAffineTransform(scaleX: self.maxScale, y: self.maxScale)
}, completion: {(finished: Bool) -> Void in
})
}
if scaleUpdated {
// Update recrangle
self.setRectangleScale(scale: tmpScale)
}
}
}
@objc func doubleTapAction(gesture: UITapGestureRecognizer) {
if gesture.state == UIGestureRecognizerState.ended {
// Store current transfrom of UIImageView
currentTransform = self.imageView.transform
var doubleTapStartCenter = self.imageView.center
var transform: CGAffineTransform! = nil
var scale: CGFloat = 2.0 // x2 double tapped
// Get current scale
let currentScale = sqrt(abs(self.imageView.transform.a * self.imageView.transform.d - self.imageView.transform.b * self.imageView.transform.c))
// Get tapped location
let tappedLocation = gesture.location(in: self.imageView)
var newCenter: CGPoint
if self.maxScale < currentScale * scale { // Upper higher scale limit
scale = self.minScale
transform = CGAffineTransform.identity
newCenter = CGPoint(x: self.baseView.frame.size.width / 2, y: self.baseView.frame.size.height / 2)
doubleTapStartCenter = newCenter
// Update recrangle
self.setRectangleScale(scale: scale)
} else {
transform = self.currentTransform!.concatenating(CGAffineTransform(scaleX: scale, y: scale))
newCenter = CGPoint(
x: doubleTapStartCenter.x - ((tappedLocation.x - doubleTapStartCenter.x) * scale - (tappedLocation.x - doubleTapStartCenter.x)),
y: doubleTapStartCenter.y - ((tappedLocation.y - doubleTapStartCenter.y) * scale - (tappedLocation.y - doubleTapStartCenter.y)))
// Update recrangle
self.setRectangleScale(scale: currentScale * scale)
}
// Update view
UIView.animate(withDuration: 0.3, delay: 0.0, options: UIViewAnimationOptions.curveEaseOut, animations: {() -> Void in
self.imageView.center = newCenter
self.imageView.transform = transform
}, completion: {(finished: Bool) -> Void in
})
}
}
}
@aceway
Copy link

aceway commented May 3, 2018

hi, guy:
I read your code, but have a question:
where is the self.setRectangleScale function definition?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment