Last active
May 3, 2018 15:12
-
-
Save mryssng/2afbc9bd2efe4706142e89e8aef6564f to your computer and use it in GitHub Desktop.
Gesture Image Zoom View Controller without UIScrollView
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// 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 | |
}) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
hi, guy:
I read your code, but have a question:
where is the self.setRectangleScale function definition?