Last active
March 15, 2019 14:25
-
-
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)
This file contains hidden or 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
// | |
// 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; | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Here is screenshot for how it's look like
