How to detect a touch on a moving (animation) UIImageView? - ios

I'm trying to add UITapGestureRecognizer on a UIImageView while its moving but the clic is only working when the animation is static.
I've looked everywhere on the internet but couldn't find a solution.
Is there a solution to this problem?
Here's the code I'm working with: I'm creating 10 "bubbles" containing a round image. I animate them so they're moving up and fading. I'd like to be able to click on them and get their tag (int form 1 to 10).
#IBAction func startBubble(sender: AnyObject) {
//var bubble = UIView()
let screenSize = UIScreen.mainScreen().bounds
let screenWidth = screenSize.width
let screenHeight = screenSize.height
// Animation parameters
let duration : NSTimeInterval = 9.0
var delay : NSTimeInterval = 1.0
var minimumDelay : NSTimeInterval = 3.0
let factor : CGFloat = 1.75
let opacity : CGFloat = 0.3
let options: UIViewAnimationOptions = [.CurveEaseIn, .AllowUserInteraction]
for bubbleNumber in 1...10 {
// Bubble size
let bubbleWidth : CGFloat = CGFloat(arc4random_uniform(40) + 130)
let bubbleHeight = bubbleWidth
// Bubble start position
let startPosition : CGFloat = CGFloat(arc4random_uniform(UInt32(screenWidth - bubbleWidth)))
// Bubble delay
if bubbleNumber > 1 {
minimumDelay = minimumDelay + NSTimeInterval(3.0)
delay = minimumDelay + (NSTimeInterval(arc4random_uniform(1000)) / 1000)
}
let bubble = UIImageView(frame: CGRectMake(startPosition, screenHeight, bubbleWidth, bubbleHeight))
// Bubble definition
bubble.image = UIImage(named: "bubble.png")
bubble.tag = bubbleNumber
bubble.userInteractionEnabled = true
bubble.addGestureRecognizer(UITapGestureRecognizer(target: self, action: "openBubble:"))
self.view.addSubview(bubble)
UIView.animateWithDuration(duration, delay: delay, options: options, animations: {
bubble.frame = CGRectMake(startPosition, 1, factor*bubbleWidth, factor*bubbleHeight)
bubble.alpha = opacity
}, completion: { animationFinished in
bubble.alpha = 0.1
bubble.removeFromSuperview()
})
}
}
func openBubble(sender:UITapGestureRecognizer){
let tappedBubble = sender.view!
print(tappedBubble.tag)
}

Related

How to add rotated gif imageview into video layer without break position in swift?

I have created video editor, where I can add sticker, text and animated gif images
but I'm getting problem to get correct position or rotated gif images, It breaks the UI and showing different place instead of actual place where it puted and rotated.
without rotated gif image working like a charm
Let me share my code
To get actual position
func gifRectToVideolayer(parentSize size: CGSize, imageFrame:CGRect, isRotated: Bool = false) -> CGRect {
var rect = CGRect(origin: CGPoint.zero, size: imageFrame.size)
let widthAspect = size.width/SCREEN_WIDTH
let heightAspect = size.height/tempImageView.height
rect.size.width = imageFrame.size.width * widthAspect
rect.size.height = imageFrame.size.height * heightAspect
rect.origin = imageFrame.origin
rect.origin.x = imageFrame.origin.x * widthAspect
rect.origin.y = size.height - ((imageFrame.origin.y * heightAspect) + rect.size.height)
return rect
}
Here is the code to get actual gif image and render it by creating new layer, I have problem with this overllayLayer rendering when imageview is rotated.
func applyVideoEffects(size: CGSize) -> CALayer {
let parentLayer = CALayer()
parentLayer.frame = CGRect(x: 0, y: 0, width: size.width, height: size.height)
// - set up the overlay for all Gif
for imageview in self.tempImageView.subviews {
print("frame of imageView: \(imageview.frame)")
if let fileUrl = (imageview as? DraggableImageView)?.gifUrl {
let overlayLayer = CALayer()
overlayLayer.frame = gifRectToVideolayer(parentSize: size, imageFrame: imageview.originalFrame)
overlayLayer.transform = CATransform3DMakeAffineTransform(imageview.transform)
startGifAnimation(with: fileUrl, in: overlayLayer)
parentLayer.addSublayer(overlayLayer)
}
}
return parentLayer;
}
Creating gif animation
func startGifAnimation(with url: URL?, in layer: CALayer?) {
let animation = animationForGif(with: url!)
if let animation = animation {
layer?.add(animation, forKey: "contents")
}
}
func animationForGif(with url: URL) -> CAKeyframeAnimation? {
let animation = CAKeyframeAnimation(keyPath: #keyPath(CALayer.contents))
var frames: [CGImage] = []
var delayTimes: [CGFloat] = []
var totalTime: CGFloat = 0.0
// var gifWidth: CGFloat, gifHeight: CGFloat
guard let gifSource = CGImageSourceCreateWithURL(url as CFURL, nil) else {
print("Can not get image source from the gif: \(url)")
return nil
}
// get frame
let frameCount = CGImageSourceGetCount(gifSource)
for i in 0..<frameCount {
guard let frame = CGImageSourceCreateImageAtIndex(gifSource, i, nil) else {
continue
}
guard let dic = CGImageSourceCopyPropertiesAtIndex(gifSource, i, nil) as? [AnyHashable: Any] else { continue }
// gifWidth = dic[kCGImagePropertyPixelWidth] as? CGFloat ?? 0
// gifHeight = dic[kCGImagePropertyPixelHeight] as? CGFloat ?? 0
guard let gifDic: [AnyHashable: Any] = dic[kCGImagePropertyGIFDictionary] as? [AnyHashable: Any] else { continue }
let delayTime = gifDic[kCGImagePropertyGIFDelayTime] as? CGFloat ?? 0
frames.append(frame)
delayTimes.append(delayTime)
totalTime += delayTime
}
if frames.count == 0 {
return nil
}
assert(frames.count == delayTimes.count)
var times: [NSNumber] = []
var currentTime: CGFloat = 0
for i in 0..<delayTimes.count {
times.append(NSNumber(value: Double(currentTime / totalTime)))
currentTime += delayTimes[i]
}
animation.keyTimes = times
animation.values = frames
animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear)
animation.duration = Double(totalTime)
animation.repeatCount = .greatestFiniteMagnitude
animation.beginTime = AVCoreAnimationBeginTimeAtZero
animation.isRemovedOnCompletion = false
return animation
}
Here is UIView extension method to get the correct frame to create new layer.
var originalFrame: CGRect {
let currentTransform = transform
transform = .identity
let originalFrame = frame
transform = currentTransform
return originalFrame
}
Hope some one can help me
Thanks in advance.

UIScrollview Animation Transition From View To View

I am trying to perform a transition animation whenever a user scrolls on a paginated view, i.e: From Page 1 to Page 2.
Unfortunately, I've not been able to replicate that.
Attach below is what I've done:
class OnboardingParallaxImageView: BaseUIView, UIScrollViewDelegate {
let allImages = [#imageLiteral(resourceName: "onboarding_handshake_icon"), #imageLiteral(resourceName: "onboarding_paylinc_icon")]
var activeCurrentPage = 1
let bgView: UIImageView = {
let image = #imageLiteral(resourceName: "onboard_bg_gradient")
let view = UIImageView(image: image)
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
let firstImageView: UIImageView = {
let view = UIImageView()
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
let secondImageView: UIImageView = {
let view = UIImageView()
view.isHidden = true
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
var firstImageHeightAnchor: NSLayoutConstraint?
var firstImageWidthAnchor: NSLayoutConstraint?
var secondImageHeightAnchor: NSLayoutConstraint?
var secondImageWidthAnchor: NSLayoutConstraint?
override func setupViews() {
super.setupViews()
addSubview(bgView)
addSubview(firstImageView)
addSubview(secondImageView)
bgView.widthAnchor.constraint(equalTo: widthAnchor).isActive = true
bgView.heightAnchor.constraint(equalTo: heightAnchor).isActive = true
bgView.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
bgView.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
firstImageWidthAnchor = firstImageView.widthAnchor.constraint(equalTo: widthAnchor)
firstImageWidthAnchor?.isActive = true
firstImageHeightAnchor = firstImageView.heightAnchor.constraint(equalTo: heightAnchor)
firstImageHeightAnchor?.isActive = true
firstImageView.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
firstImageView.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
firstImageView.image = allImages[0]
secondImageWidthAnchor = secondImageView.widthAnchor.constraint(equalTo: widthAnchor)
secondImageWidthAnchor?.isActive = true
secondImageHeightAnchor = secondImageView.heightAnchor.constraint(equalTo: heightAnchor)
secondImageHeightAnchor?.isActive = true
secondImageView.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
secondImageView.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
secondImageView.image = allImages[1]
}
override func layoutSubviews() {
super.layoutSubviews()
let frameWidth = frame.size.width
secondImageHeightAnchor?.constant = -(frameWidth - 32)
secondImageWidthAnchor?.constant = -(frameWidth - 32)
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let offSet = scrollView.contentOffset.x
let frameWidth = frame.size.width / 2
let toUseConstant = (CGFloat(abs(offSet)) / frameWidth)
if activeCurrentPage == 1 {
if offSet <= 0 {
firstImageHeightAnchor?.constant = 0
firstImageWidthAnchor?.constant = 0
firstImageView.isHidden = false
secondImageView.isHidden = true
} else {
firstImageHeightAnchor?.constant += -(toUseConstant)
firstImageWidthAnchor?.constant += -(toUseConstant)
firstImageView.isHidden = false
secondImageHeightAnchor?.constant += -(toUseConstant)
secondImageWidthAnchor?.constant += -(toUseConstant)
secondImageView.isHidden = false
secondImageView.alpha = toUseConstant
}
}
UIView.animate(withDuration: 0.5) {
self.layoutSubviews()
}
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
self.activeCurrentPage = scrollView.currentPage
}
}
This is the result of what I've been able to achieve:
How can I go about transitioning from A to B without any funny behaviour.
Thanks
The easiest way to achieve smooth behaviour is using UIViewPropertyAnimator.
Setup the initial values for each image view:
override func viewDidLoad() {
super.viewDidLoad()
firstImageView.image = // your image
secondImageView.image = // your image
secondImageView.transform = CGAffineTransform(scaleX: 0.01, y: 0.01)
secondImageView.alpha = 0
}
Then create property animator for each imageView
lazy var firstAnimator: UIViewPropertyAnimator = {
// You can play around with the duration, curve, damping ration, timing
let animator = UIViewPropertyAnimator(duration: 2, curve: .easeIn, animations: {
self.firstImageView.image.transform = CGAffineTransform(scaleX: 0.01, y: 0.01)
self.firstImageView.image.alpha = 0
})
return animator
}()
and the second one
lazy var secondAnimator: UIViewPropertyAnimator = {
let animator = UIViewPropertyAnimator(duration: 2, curve: .easeIn, animations: {
self.secondImageView.transform = CGAffineTransform(scaleX: 1, y: 1)
self.secondImageView.alpha = 1
})
return animator
}()
now on scrollViewDidScroll when you have calculated the completed percent just update the animators:
firstAnimator.fractionComplete = calculatedPosition
secondAnimator.fractionComplete = calculatedPosition
You can apply the same approach for multiple views
You might want to consider using a Framework for this instead of reinventing the wheel. Something like Hero for example.
There as some basic examples to get you started. Essentially this provides you an easy to use option to code transition behavior between two UIViewControllers by defining how each UI-Component should behave base on the transition progress.
I have achieved it using the keyframe animation on ImageView's frame. But you can also achieve it using the constraint based animation as you tried. Just replace the frames size variations that I have done here with the change in constraint's constants as per your convenience.
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var imgView1: UIImageView! //HANDSHAKE image on TOP
#IBOutlet weak var imgView2: UIImageView! //CREDIT_CARD and PHONE image
#IBOutlet weak var imgView3: UIImageView! //SINGLE_HAND image
let minimumFrameSize = CGSize(width: 0.0, height: 0.0)
let meetingPointFrameSize = CGSize(width: 150.0, height: 150.0)
let maximumFrameSize = CGSize(width: 400.0, height: 400.0)
override func viewDidLoad() {
super.viewDidLoad()
let centerOfImages = CGPoint(x: self.view.frame.width/2 , y: self.view.frame.height/2)
//initial state
self.imgView1.frame.size = maximumFrameSize
self.imgView1.alpha = 1.0
self.imgView2.frame.size = minimumFrameSize
self.imgView2.alpha = 0.0
self.imgView3.frame.size = minimumFrameSize
self.imgView3.alpha = 0.0
self.imgView1.center = centerOfImages
self.imgView2.center = centerOfImages
self.imgView3.center = centerOfImages
UIView.animateKeyframes(withDuration: 5.0, delay: 2.0, options: [UIView.KeyframeAnimationOptions.repeat,
UIView.KeyframeAnimationOptions.calculationModeLinear],
animations: {
UIView.addKeyframe(withRelativeStartTime: 0.0, relativeDuration: 0.25, animations: {
self.imgView1.frame.size = self.meetingPointFrameSize
self.imgView1.alpha = 0.3
self.imgView1.center = centerOfImages
self.imgView2.frame.size = self.meetingPointFrameSize
self.imgView2.alpha = 0.3
self.imgView2.center = centerOfImages
/*image 1 and image 2 meets at certain point where
image 1 is decreasing its size and image 2 is increasing its size simultaneously
*/
})
UIView.addKeyframe(withRelativeStartTime: 0.25, relativeDuration: 0.25, animations: {
self.imgView1.frame.size = self.minimumFrameSize
self.imgView1.alpha = 0.0
self.imgView1.center = centerOfImages
self.imgView2.frame.size = self.maximumFrameSize
self.imgView2.alpha = 1.0
self.imgView2.center = centerOfImages
/* image 1 has decreased its size to zero and
image 2 has increased its size to maximum simultaneously
*/
})
UIView.addKeyframe(withRelativeStartTime: 0.4, relativeDuration: 0.1, animations: {
self.imgView2.frame.size = self.maximumFrameSize
self.imgView2.alpha = 1.0
self.imgView2.center = centerOfImages
/* Hold for a moment
*/
})
UIView.addKeyframe(withRelativeStartTime: 0.6, relativeDuration: 0.15, animations: {
self.imgView2.frame.size = self.meetingPointFrameSize
self.imgView2.alpha = 0.3
self.imgView2.center = centerOfImages
self.imgView3.frame.size = self.meetingPointFrameSize
self.imgView3.alpha = 0.3
self.imgView3.center = centerOfImages
/*image 2 and image 3 meets at certain point where
image 2 is decreasing its size and image 3 is increasing its size simultaneously
*/
})
UIView.addKeyframe(withRelativeStartTime: 0.75, relativeDuration: 0.25, animations: {
self.imgView2.frame.size = self.minimumFrameSize
self.imgView2.alpha = 0.0
self.imgView2.center = centerOfImages
self.imgView3.frame.size = self.maximumFrameSize
self.imgView3.alpha = 1.0
self.imgView3.center = centerOfImages
/* image 2 has decreased its size to zero and
image 3 has increased its size to maximum simultaneously
*/
})
}) { (finished) in
/*If you have any doubt or need more enhancement or in case you need my project. Feel free to ask me.
Please ping me on skype/email:
ojhashubham29#gmail.com
or connect me on Twitter
#hearthackman
*/
}
}
}

Swift, animate to specific CGPoint

How could I animate programatically created object to go to a specific CGPoint. Not using CGAffineTransformMakeTranslation, as this is just on how to move it, not exactly where to move it.
I have tried: translatesAutoresizingMaskIntoConstraints = true
But it makes no difference.
I have tried this:
//Define screen sizes
let screenSize: CGRect = UIScreen.mainScreen().bounds
let screenWidth = screenSize.width
let screenHeight = screenSize.height
// Sizes of centre cards
let centreCardWidth = screenWidth/5
let centreCardHeight = (screenWidth/5) / 0.625
let centralizeViewHorizontalCard = (screenWidth/2) - ((screenWidth/5) / 2)
let centralizeViewVerticleCard = screenHeight / 2
UIView.animateWithDuration(0.25, delay: 0.5, options: [], animations: {
centreCard3.frame = CGRectMake(centralizeViewHorizontalCard, centralizeViewVerticleCard, centreCard3.frame.size.width, centreCard3.frame.size.height)
}, completion: nil)
But when run in the simulator, absolutely nothing happened.
Your UI hasn't rendered yet when you are animating. Put it in viewDidAppear. This works for me:
class ViewController: UIViewController {
#IBOutlet weak var centreCard3: UIView!
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(animated: Bool) {
let screenSize: CGRect = UIScreen.mainScreen().bounds
let screenWidth = screenSize.width
let screenHeight = screenSize.height
// Sizes of centre cards
let centralizeViewHorizontalCard = (screenWidth/2) - ((screenWidth/5) / 2)
let centralizeViewVerticleCard = screenHeight / 2
UIView.animateWithDuration(0.5, delay: 0.5, options: [], animations: {
self.centreCard3.frame = CGRectMake(centralizeViewHorizontalCard, centralizeViewVerticleCard, self.centreCard3.frame.size.width, self.centreCard3.frame.size.height)
}, completion: nil)
}
}
Result:

Double sided UIView not working

I have a subclass of UIView called TitleView, all this subclass does is override layerClass to return CATransformLayer.
My titleView property has some subviews; a titleBackgroundView and a titleLabel.
When I run my code the titleView’s top layer is visible (green background), but when I run my flip animation, there’s no animation. The code just jumps to the end state. Furthermore there’s no bottom layer visible (red background), just a reversed version of the titleView (a transformed titleLabel).
In the IBOutlet setter I have the following code:
#IBOutlet private weak var titleView: TitleView! {
didSet {
titleView.backgroundColor = UIColor.clearColor()
let topLayer = CALayer()
topLayer.backgroundColor = UIColor.greenColor().CGColor
topLayer.frame = titleView.bounds
topLayer.doubleSided = false
topLayer.zPosition = 3
titleView.layer.addSublayer(topLayer)
let bottomLayer = CALayer()
bottomLayer.backgroundColor = UIColor.redColor().CGColor
bottomLayer.frame = titleView.bounds
bottomLayer.doubleSided = false
bottomLayer.zPosition = 2
bottomLayer.transform = CATransform3DMakeRotation(CGFloat(M_PI), 1, 0, 0)
titleView.layer.addSublayer(bottomLayer)
}
}
titleView animation code:
private func setIsCategoriesShowing(showCategories: Bool, animated: Bool)
{
let alreadyInFinishState = (isShowingCategories == showCategories) ? true : false
if alreadyInFinishState
{
return
}
// Setup animations
isAnimatingCategories = true
headerView.superview?.bringSubviewToFront(headerView)
titleView.layer.setAnchorPointDynamically(CGPoint(x: 0.5, y: 1)) // Change position when updating anchor point
// Animate
let duration: NSTimeInterval = animated ? 0.8 : 0
let options: UIViewAnimationOptions = (showCategories == true) ? [.CurveEaseIn] : [.CurveEaseOut]
let newRotationValue: CGFloat = (showCategories == true) ? -179 : 0
let damping: CGFloat = (showCategories == true) ? 0.7 : 1
let initialSpringVelocity: CGFloat = (showCategories == true) ? 0.5 : 1
UIView.animateWithDuration(duration,
delay: 0,
usingSpringWithDamping: damping,
initialSpringVelocity: initialSpringVelocity,
options: options,
animations: { () -> Void in
var rotationAndPerspectiveTransform = CATransform3DIdentity
rotationAndPerspectiveTransform.m34 = 1 / -500
rotationAndPerspectiveTransform = CATransform3DRotate(rotationAndPerspectiveTransform, newRotationValue, 1, 0, 0);
self.titleView.layer.sublayerTransform = rotationAndPerspectiveTransform;
}) { (success) -> Void in
if showCategories == false
{
self.titleView.layer.sublayerTransform = CATransform3DIdentity
}
self.isAnimatingCategories = false
self.isShowingCategories = showCategories
}
}
Okay, so given a series of trial and error I’ve managed to (it seems) fix my problem. Feel free to take a look…
Here is the working code:
#IBOutlet private weak var titleView: TitleView! {
didSet {
let bottomLayer = CALayer()
bottomLayer.backgroundColor = UIColor.redColor().CGColor
bottomLayer.frame = titleView.bounds
bottomLayer.doubleSided = false
bottomLayer.zPosition = 2
bottomLayer.transform = CATransform3DMakeRotation(CGFloat(M_PI), 0, 1, 0) // Reverse bottom layer, so when flipped it's visible.
titleView.layer.addSublayer(bottomLayer)
// All subviews are one-sided
for subview in titleView.subviews
{
subview.layer.doubleSided = false
}
}
}
#IBOutlet private weak var titleViewBackgroundView: UIView!
Animation code:
private func setIsCategoriesShowing(showCategories: Bool, animated: Bool)
{
let alreadyInFinishState = (isShowingCategories == showCategories) ? true : false
if alreadyInFinishState
{
return
}
// Housekeeping
headerView.superview?.bringSubviewToFront(headerView)
titleView.layer.setAnchorPointDynamically(CGPoint(x: 0.5, y: 1))
// Animate
isAnimatingCategories = true
let isOpening = (showCategories == true)
let duration: NSTimeInterval = animated ? 3 : 0
let damping: CGFloat = isOpening ? 0.7 : 1
let initialSpringVelocity: CGFloat = isOpening ? 0.5 : 1
let options: UIViewAnimationOptions = isOpening ? [.CurveEaseIn] : [.CurveEaseOut]
let newRotationValue: CGFloat = isOpening ? -179 : 0
var rotationAndPerspectiveTransform = CATransform3DIdentity
rotationAndPerspectiveTransform.m34 = 1 / -500
rotationAndPerspectiveTransform = CATransform3DRotate(rotationAndPerspectiveTransform, newRotationValue, 1, 0, 0);
UIView.animateWithDuration(duration,
delay: 0,
usingSpringWithDamping: damping,
initialSpringVelocity: initialSpringVelocity,
options: options,
animations: {
self.titleView.layer.transform = rotationAndPerspectiveTransform;
}) { (success) -> Void in
if !isOpening
{
self.titleView.layer.transform = CATransform3DIdentity
}
self.isAnimatingCategories = !success
self.isShowingCategories = showCategories
}
}

TextView inside ScrollView stick to keyboard

I have a UIScrollView and content inside it. Inside content there is a UITextView. When user presses the UITextView I want the UITextView stick to the keyboard.
In the image:
Whole thing is UIScrollView
Bottom black area is the visible screen
Red area is content
Blue area is UITextView
Green distance is the dynamic margin between content and the screen bound.
I want to calculate the green distance which the user can see along with the blue are(UITextView) which the user can see. If the user half swiped UITextView, the UITextView should still stick to the keyboard.
let userInfo = notification.userInfo!
let keyboardEndFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as NSValue).CGRectValue()
let keyboardBeginFrame = (userInfo[UIKeyboardFrameBeginUserInfoKey] as NSValue).CGRectValue()
let curve = userInfo[UIKeyboardAnimationCurveUserInfoKey] as UInt
let duration = userInfo[UIKeyboardAnimationDurationUserInfoKey] as Double
let options = UIViewAnimationOptions(curve << 16)
UIView.animateWithDuration(duration, delay: 0, options: options,
animations: {
var visibleGreen = ???
var visibleBlue = ???
var amountToSubtract = visibleGreen + visibleBlue
var newFrame = (self.currentCardInstance?.newCommentCell.frame)!
var kbFrameEnd = self.view.convertRect(keyboardEndFrame, toView: nil)
var kbFrameBegin = self.view.convertRect(keyboardBeginFrame, toView: nil)
newFrame.origin.y -= kbFrameBegin.origin.y - kbFrameEnd.origin.y + amountToSubtract
self.currentCardInstance?.newCommentCell.frame = newFrame;
},
completion: nil
)
Here is how I solved it:
var keyboardModifier: CGFloat = 0
func keyboardWillAppear(notification: NSNotification) {
println("keyboardWillAppear")
keyboardResize(notification: notification)
scrollToBottom()
}
func keyboardWillDisappear(notification: NSNotification) {
println("keyboardWillDisappear")
keyboardResize(notification: notification)
}
func keyboardResize(#notification: NSNotification) {
let userInfo = notification.userInfo!
let keyboardEndFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as NSValue).CGRectValue()
let keyboardBeginFrame = (userInfo[UIKeyboardFrameBeginUserInfoKey] as NSValue).CGRectValue()
let curve = userInfo[UIKeyboardAnimationCurveUserInfoKey] as UInt
let duration = userInfo[UIKeyboardAnimationDurationUserInfoKey] as Double
let options = UIViewAnimationOptions(curve << 16)
var newFrame = (self. currentCardInstance?.frame)!
var kbFrameEnd = self.view.convertRect(keyboardEndFrame, toView: nil)
var kbFrameBegin = self.view.convertRect(keyboardBeginFrame, toView: nil)
keyboardModifier = kbFrameBegin.origin.y - kbFrameEnd.origin.y
scrollView.frame.size.height -= keyboardModifier
}
func scrollToBottom() {
var bottomOffset = CGPoint(x: 0, y: scrollView.contentSize.height - scrollView.bounds.size.height)
scrollView.setContentOffset(bottomOffset, animated: false)
}

Resources