Skip to content

Instantly share code, notes, and snippets.

@Coder-ACJHP
Last active March 15, 2019 14:25
Show Gist options
  • Save Coder-ACJHP/20d4da90c9028e2181d2a229425f851a to your computer and use it in GitHub Desktop.
Save Coder-ACJHP/20d4da90c9028e2181d2a229425f851a to your computer and use it in GitHub Desktop.
Anmiation : - Apply zoom out and bounce animation together when user tap on view and swipe down to reverse animation (like in Photo library of IOS)
//
// ZoomOutAndBounceVC.swift
// Cartoonize Image
//
// Created by Coder ACJHP on 15.03.2019.
// Copyright © 2019 Onur Işık. All rights reserved.
//
// ********************************************************************
// Be careful and don't use AutoLayout Constraints for animating view *
// This animations works with AutoResizing only! *
// ********************************************************************
import UIKit
class ZoomOutAndBounceVC: UIViewController, UIGestureRecognizerDelegate {
// Outlets for this example I'm gonna use imageViews
// ********************************************************************
// AGAIN!! Be careful and don't use AutoLayout Constraints for *
// animating view This animations works with AutoResizing only! *
// ********************************************************************
@IBOutlet var imageViewsCollection: [UIImageView]!
// Store animation state
var isAlreadyAnimated: Bool = false
// Store view center position before animation
var oldCenter: CGPoint = CGPoint.zero
// Store view center position before pan began
var initialTouchPoint: CGPoint = CGPoint.zero
// Apply blur effect behind focused image view
lazy var blurView: UIVisualEffectView = {
let blurEffectView = UIVisualEffectView(effect: UIBlurEffect(style: .prominent))
blurEffectView.frame = self.view.frame
blurEffectView.alpha = 0
return blurEffectView
}()
override func viewDidLoad() {
super.viewDidLoad()
// Optional
self.view.backgroundColor = .orange
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// Setup image views (add gesture regognizers etc.)
setupImageViews()
}
private func setupImageViews() {
self.imageViewsCollection.forEach { (imageView) in
imageView.isUserInteractionEnabled = true
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:)))
tapGestureRecognizer.numberOfTapsRequired = 1
tapGestureRecognizer.delegate = self
imageView.addGestureRecognizer(tapGestureRecognizer)
let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(panGestureRecognizerHandler(_:)))
panGestureRecognizer.delegate = self
imageView.addGestureRecognizer(panGestureRecognizer)
panGestureRecognizer.require(toFail: tapGestureRecognizer)
}
}
@objc private func handleTap(_ gestureRecognizer: UITapGestureRecognizer) {
// be sure gesture view is not empty and it kind of image view class
guard let tappedView = gestureRecognizer.view, tappedView.isKind(of: UIImageView.self) else { return }
// if view isn't animated in advance
if !isAlreadyAnimated {
// add blur view as a subview to main view
if self.blurView.superview == nil {
view.addSubview(blurView)
blurView.center = view.center
// store old position of animating view
oldCenter = tappedView.center
view.bringSubview(toFront: tappedView)
}
UIView.animate(withDuration: 1.0, delay: 0.0,
usingSpringWithDamping: 1.0,
initialSpringVelocity: 1.0,
options: [.curveEaseInOut],
animations: {
self.blurView.alpha = 1.0
// equal center of animating view with blurView center
tappedView.center = self.blurView.center
// and make it bigger
tappedView.transform = CGAffineTransform.init(scaleX: 1.6, y: 1.6)
}, completion: nil)
// Set this variable as view is animated
self.isAlreadyAnimated = true
} else {
// User tapped on image again so in this case we will restore view position and scale
UIView.animate(withDuration: 1.0, delay: 0.0,
usingSpringWithDamping: 1.0,
initialSpringVelocity: 1.0,
options: [.curveEaseInOut],
animations: {
self.blurView.alpha = 0.0
tappedView.center = self.oldCenter
tappedView.transform = CGAffineTransform.identity
}, completion: { (_) in
self.blurView.removeFromSuperview()
})
isAlreadyAnimated = false
}
}
@objc private func panGestureRecognizerHandler(_ gestureRecognizer: UIPanGestureRecognizer) {
guard let pannedView = gestureRecognizer.view, pannedView.isKind(of: UIImageView.self) else { return }
let touchPoint = gestureRecognizer.location(in: self.view?.window)
// In this case user tapped on image
if isAlreadyAnimated {
// Let check user swiping it down to dismiss it ?
switch gestureRecognizer.state {
case .began:
// Store old center to use it after
initialTouchPoint = touchPoint
case .changed:
// Current touch point is greater than old and smaller than 100
// Because 100 is good value to allowing swipe distance
// finally check if new y point is greater than old y (user swiping down?)
if touchPoint.y - initialTouchPoint.y > 0 &&
touchPoint.y - initialTouchPoint.y < 100 &&
touchPoint.y > blurView.center.y {
pannedView.center = CGPoint(x: initialTouchPoint.x, y: touchPoint.y)
} else { return }
case .ended, .cancelled:
// Swipped distance greater than 50 and current y point is greater than old y point ?
if touchPoint.y - initialTouchPoint.y > 50
&& touchPoint.y > blurView.center.y {
UIView.animate(withDuration: 1.0, delay: 0.0,
usingSpringWithDamping: 1.0,
initialSpringVelocity: 1.0,
options: [.curveEaseInOut],
animations: {
self.blurView.alpha = 0.0
pannedView.center = self.oldCenter
pannedView.transform = CGAffineTransform.identity
}, completion: { (_) in
self.blurView.removeFromSuperview()
self.isAlreadyAnimated = false
})
} else {
// None of them thats mean return view to it's old position without dismissing
UIView.animate(withDuration: 1.0, delay: 0.0,
usingSpringWithDamping: 1.0,
initialSpringVelocity: 1.0,
options: [.curveEaseInOut],
animations: {
pannedView.center = self.blurView.center
}, completion: nil)
}
default: break;
}
}
}
}
@Coder-ACJHP
Copy link
Author

Here is screenshot for how it's look like
ZoomOut Bounce

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