How to make a bounce effect for a button - ios

I'm trying to make a bounce effect for a button in view will appear. I want my button to do something like this
How to create a UIView bounce animation?
I'm doing this with this code but it isn't fluid...
UIView.animateWithDuration(0.5, delay: 0.0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: [], animations: ({
self.image.center.y = self.view.frame.height / 4
}), completion: nil)
UIView.animateWithDuration(0.7, delay: 0.2, usingSpringWithDamping: 1, initialSpringVelocity: 0.8, options: [], animations: ({
self.image.center.y = self.view.frame.height / 6
}), completion: nil)
UIView.animateWithDuration(0.9, delay: 0.4, usingSpringWithDamping: 1, initialSpringVelocity: 0.6, options: [], animations: ({
self.image.center.y = self.view.frame.height / 4
}), completion: nil)
UIView.animateWithDuration(1, delay: 0.6, usingSpringWithDamping: 1, initialSpringVelocity: 0.4, options: [], animations: ({
self.image.center.y = self.view.frame.height / 5.5
}), completion: nil)
UIView.animateWithDuration(1.05, delay: 0.8, usingSpringWithDamping: 1, initialSpringVelocity: 0.2, options: [], animations: ({
self.image.center.y = self.view.frame.height / 4
}), completion: nil)

Instead of nesting all the animations inside the first animation block, put each consecutive animation in the completion handler of the one before it.
Although i would recommend using Core Animation for something like this as opposed to the UIView animateWithDuration method.

you can use the below class for easy use
class BounceButton: UIButton {
#IBInspectable var baseColor: String = "2"{
didSet {
//layer.borderColor = borderColor.CGColor
if baseColor == "1" {
self.backgroundColor = UIColor.MiTheme.BtnColorPrimary
self.setTitleColor(UIColor.white, for: .normal)
self.titleLabel?.font = UIFont.boldSystemFont(ofSize: 17)
}
else if baseColor == "2" {
self.backgroundColor = UIColor.MiTheme.BtnColorSecond
self.setTitleColor(UIColor.black, for: .normal)
}
else if baseColor == "3" {
self.backgroundColor = UIColor.black
self.setTitleColor(UIColor.white, for: .normal)
self.titleLabel?.font = UIFont.boldSystemFont(ofSize: 17)
}
else if baseColor == "4" {
}
}
}
override init(frame: CGRect) {
super.init(frame: frame)
//self.layer.cornerRadius = 28.5
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
//self.layer.cornerRadius = 28.5
}
// Add some animations on button click
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesBegan(touches, with: event)
// Scale up the button
self.transform = CGAffineTransform(scaleX: 1.1, y: 1.1)
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 6, options: .allowUserInteraction, animations: {
// Reset the sizes to defaults
self.transform = CGAffineTransform.identity
}, completion: nil)
}
}

Related

Unwanted button preview before animation during transition to second controller

In a navigation controller embedded project, using animations, I cannot avoid getting a "fast preview" of the buttons present in the next ViewController, where those buttons will slide from left border of the screen to the center.
So, when I tap in first VC, see for an instant the buttons in second VC, and then the second VC appears and the animation works (and it works fine)
In home controller the button is:
#objc func imageTapped(tapGestureRecognizer: UITapGestureRecognizer)
{
print("tapped")
//animate 1/2
UIView.animate(withDuration: 0.8, animations: { () -> Void in
self.mainButtonContainerView.center.y -= self.view.bounds.width //self.view.frame.origin
self.mainButtonContainerView.isUserInteractionEnabled = false
self.mainButtonContainerView.alpha = 0.0
})
//animate2/2
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(1) ) {
self.pushShowNextVC_ChoiceVC(dataToPass: "")
}
}
Then, the animation in second VC ViewDidLoad is:
for singleView in coantinersOutCollection {
//animation
singleView.center.x -= self.view.bounds.width
singleView.layer.cornerRadius = singleView.bounds.size.height/2
singleView.backgroundColor = UIColor.white
singleView.layer.borderColor = Constants.skyBlue3Color.cgColor
singleView.layer.borderWidth = 1
}
for singleLabel in labesForButtons {
singleLabel.textColor = Constants.skyBlue3Color
singleLabel.font = UIFont.boldSystemFont(ofSize: 17.0)
}
for singleImage in self.iconButtonImages {
// singleImage.image = UIImage(named: "")
singleImage.backgroundColor = UIColor.clear
singleImage.layer.borderWidth = 1
singleImage.layer.borderColor = Constants.skyBlue3Color.cgColor
}
UIView.animate(withDuration: 1.5, delay: 0.6,
usingSpringWithDamping: 0.6,
initialSpringVelocity: 1,
options: [], animations: {
self.containerDownloadButton.center.x += self.view.bounds.width
}, completion: nil)
UIView.animate(withDuration: 1.5, delay: 0.7,
usingSpringWithDamping: 0.6,
initialSpringVelocity: 1,
options: [], animations: {
self.containerUploadButton.center.x += self.view.bounds.width
}, completion: nil)
UIView.animate(withDuration: 1.5, delay: 0.8,
usingSpringWithDamping: 0.6,
initialSpringVelocity: 1,
options: [], animations: {
self.containerCallButton.center.x += self.view.bounds.width
}, completion: nil)
UIView.animate(withDuration: 1.5, delay: 0.9,
usingSpringWithDamping: 0.6,
initialSpringVelocity: 1,
options: [], animations: {
self.containerIdleButton.center.x += self.view.bounds.width
}, completion: nil)

iOS - Type 'UIView' has no member 'AnimationOptions'

I am using TextFieldEffects to add text inputs effects in my textField. it is showing an error
Type 'UIView' has no member 'AnimationOptions'
Here's code.
override open func animateViewsForTextEntry() {
borderLayer.frame.origin = CGPoint(x: 0, y: font!.lineHeight)
UIView.animate(withDuration: 0.2, delay: 0.3, usingSpringWithDamping: 0.8, initialSpringVelocity: 1.0, options: UIView.AnimationOptions.beginFromCurrentState, animations: ({
self.placeholderLabel.frame.origin = CGPoint(x: self.placeholderInsets.x, y: self.borderLayer.frame.origin.y - self.placeholderLabel.bounds.height)
self.borderLayer.frame = self.rectForBorder(self.borderThickness, isFilled: true)
}), completion: { _ in
self.animationCompletionHandler?(.textEntry)
})
}
override open func animateViewsForTextDisplay() {
if text!.isEmpty {
UIView.animate(withDuration: 0.35, delay: 0.0, usingSpringWithDamping: 0.8, initialSpringVelocity: 2.0, options: UIView.AnimationOptions.beginFromCurrentState, animations: ({
self.layoutPlaceholderInTextRect()
self.placeholderLabel.alpha = 1
}), completion: { _ in
self.animationCompletionHandler?(.textDisplay)
})
borderLayer.frame = rectForBorder(borderThickness, isFilled: false)
}
}
Here's a screenshot of the error.
How to solve this issue?
It should be UIViewAnimationOptions.beginFromCurrentState, at least in Xcode < version 10.
Try changing UIView.AnimationOptions.beginFromCurrentState to [.beginFromCurrentState].

iOS simulator ghost image edge left over on the screen after animation

I added spring option to an UIImage. It worked fine on my phone, very nice. Bouncy and smooth.
But when I run it on the iOS simulators, it always leaves some edges on the screen.
It becomes a problem when I need to upload screenshots to App Store.
This is my code:
let theTile = numberTile
let bounds = theTile.bounds
UIView.animate(withDuration: 1, delay: 0, usingSpringWithDamping: 0.2, initialSpringVelocity: 10, options: [.curveEaseInOut, .allowUserInteraction], animations: {
theTile.bounds = CGRect(x: bounds.origin.x, y: bounds.origin.y, width: bounds.size.width * 1.2, height: bounds.size.height * 1.2)
}, completion: nil)
This is the shrink back code
let theTile = numberTile
let bounds = theTile.bounds
UIView.animate(withDuration: 0.3, delay: 0, options: .allowUserInteraction, animations: {
theTile.bounds = CGRect(origin: bounds.origin, size: self.size)
}, completion: nil)
Try this although this might not be your only issue. If that is a collection view I would need to see your cell for row function as you may be loading a cell with the bounds messed up to start with. Here is a suggestion though. Animate the transform instead.
//to animate larger
UIView.animate(withDuration: 1, delay: 0, usingSpringWithDamping: 0.2,initialSpringVelocity: 10, options: [.curveEaseInOut, .allowUserInteraction], animations: {
theTile.transform = CGAffineTransform(scaleX: 1.2, y: 1.2)
}, completion: nil)
//animate smaller
UIView.animate(withDuration: 1, delay: 0, usingSpringWithDamping: 0.2, initialSpringVelocity: 10, options: [.curveEaseInOut, .allowUserInteraction], animations: {
theTile.transform = .identity
}, completion: nil)
If this is a collection view in cell for row you may need to check for selected index but def if not selected you need to set the transform to identity.
EDIT:
You say this does not fix the issue. What environment are you running? Type of Mac. I personally believe it is a code issue somewhere else as I have written tons of animation code and never seen this bug. Here is a minimum example that does not create "ghost layers" on my device or simulator. If you can make a minimal example that does it would help a lot... Until then I think it is something in your code possibly your collection view.
import UIKit
class ViewController: UIViewController {
lazy var box : UIView = {
let v = UIView(frame: CGRect(x: 0, y: 0, width: 80, height: 80))
v.backgroundColor = .blue
v.center = self.view.center
return v
}()
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = .lightGray
self.view.addSubview(box)
box.layer.cornerRadius = 8
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
fireEvent()
super.touchesBegan(touches, with: event)
}
func fireEvent(){
if box.transform == .identity{
//to animate larger
UIView.animate(withDuration: 1, delay: 0, usingSpringWithDamping: 0.2,initialSpringVelocity: 10, options: [.curveEaseInOut, .allowUserInteraction], animations: {
self.box.transform = CGAffineTransform(scaleX: 1.2, y: 1.2)
}, completion: nil)
}else{
//animate smaller
UIView.animate(withDuration: 1, delay: 0, usingSpringWithDamping: 0.2, initialSpringVelocity: 10, options: [.curveEaseInOut, .allowUserInteraction], animations: {
self.box.transform = .identity
}, completion: nil)
}
}
}

How do I set the status bar in iOS to show a message?

I'm looking to set a message just below the status bar, and possibly changing the color of the message (see photo - am looking to set a message where "Sleep Cycle" is at).
However, I've looked at iOS' Human Design Guidelines, but am unable to ascertain what this control is called.
https://developer.apple.com/ios/human-interface-guidelines/ui-bars/navigation-bars/
Just a point in the right direction will be of great help.
Try this code: Code tested in Xcode 8.
/Update your plist with below code
View controller-based status bar appearance = NO
//In your VC:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
title = "Some Title"
navigationController?.navigationBar.tintColor = UIColor.white
navigationController?.navigationBar.barTintColor = UIColor.red
navigationController?.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName:UIColor.white]
UIApplication.shared.statusBarStyle = .lightContent // To change your status bar to display light content (In white colour)
}
func sleepCycleNotify() {
// To set BannerView
let barView = UIView(frame: CGRect(x:0, y:0, width:view.frame.width, height:(UINavigationController().navigationBar.frame.height)))
barView.backgroundColor=UIColor.red // set to any colour you want..
navigationController?.navigationBar.addSubview(barView)
let notifyLabel = UILabel()
notifyLabel.frame = CGRect(x:0, y:0, width:view.frame.width, height:(UINavigationController().navigationBar.frame.height))
notifyLabel.backgroundColor=UIColor.clear
notifyLabel.text = "Sleep Cycle"
notifyLabel.textAlignment = .center
notifyLabel.textColor = UIColor.white
notifyLabel.alpha = 0.8
barView.addSubview(notifyLabel)
// Animation 1:
// To achive animation
barView.center.y -= (navigationController?.navigationBar.bounds.height)!
UIView.animate(withDuration: 0.7, delay: 0, usingSpringWithDamping: 0.9, initialSpringVelocity: 0.6, options: UIViewAnimationOptions.curveEaseIn, animations:{
barView.center.y += (self.navigationController?.navigationBar.frame.height)!
}, completion:{ finished in
UIView.animate(withDuration: 1, delay: 1.5, usingSpringWithDamping: 0.6, initialSpringVelocity: 0.9, options: UIViewAnimationOptions.curveEaseOut, animations:{
barView.center.y -= ((self.navigationController?.navigationBar.frame.height)! + UIApplication.shared.statusBarFrame.height)
}, completion: nil)
})
}
Output from above code:
//Animation 2:
func sleepCycleNotify() {
//
let barView = UIView(frame: CGRect(x:0, y:0, width:view.frame.width, height:(UINavigationController().navigationBar.frame.height)))
barView.backgroundColor=UIColor.red // set any colour you want..
navigationController?.navigationBar.addSubview(barView)
let notifyLabel = UILabel()
notifyLabel.frame = CGRect(x:0, y:0, width:view.frame.width, height:(UINavigationController().navigationBar.frame.height))
notifyLabel.backgroundColor=UIColor.clear
notifyLabel.text = "Sleep Cycle"
notifyLabel.textAlignment = .center
notifyLabel.textColor = UIColor.white
notifyLabel.alpha = 0.8
barView.addSubview(notifyLabel)
// To achive animation
barView.center.y -= (navigationController?.navigationBar.bounds.height)!
UIView.animate(withDuration: 1, delay: 0, usingSpringWithDamping: 0.9, initialSpringVelocity: 0.6, options: UIViewAnimationOptions.curveEaseIn, animations:{
UIApplication.shared.isStatusBarHidden = true
UINavigationController().navigationBar.isHidden = true
barView.center.y += (self.navigationController?.navigationBar.frame.height)!
}, completion:{ finished in
UIView.animate(withDuration: 1.5, delay: 0, usingSpringWithDamping: 0.6, initialSpringVelocity: 0.9, options: UIViewAnimationOptions.curveEaseOut, animations:{
// notifyLabel.alpha = 0...1
UIApplication.shared.isStatusBarHidden = false
UINavigationController().navigationBar.isHidden = false
barView.center.y -= ((self.navigationController?.navigationBar.frame.height)! + UIApplication.shared.statusBarFrame.height)
}, completion: nil)
})
}
Output from animation 2:
Improved Answer:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
title = "Some Title"
navigationController?.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName:UIColor.white]
navigationController?.navigationBar.barTintColor = UIColor.purple
UIApplication.shared.statusBarStyle = .lightContent
}
func sleepCycleNotify() {
// To set BannerView
let barView = UIView(frame: CGRect(x:0, y:-UIApplication.shared.statusBarFrame.height, width:view.frame.width, height:(UINavigationController().navigationBar.frame.height) + UIApplication.shared.statusBarFrame.height ))
barView.backgroundColor=UIColor.red // set to any colour you want..
navigationController?.navigationBar.addSubview(barView)
let notifyLabel = UILabel()
notifyLabel.frame = CGRect(x:0, y:UIApplication.shared.statusBarFrame.height, width:view.frame.width, height:(UINavigationController().navigationBar.frame.height))
notifyLabel.backgroundColor=UIColor.clear
notifyLabel.numberOfLines = 0
notifyLabel.text = "Sleep Cycle"
notifyLabel.textAlignment = .center
notifyLabel.textColor = UIColor.white
notifyLabel.alpha = 0.8
barView.addSubview(notifyLabel)
// Animation 1:
// To achive animation
barView.center.y -= (navigationController?.navigationBar.bounds.height)!
UIView.animate(withDuration: 0.7, delay: 0, usingSpringWithDamping: 0.9, initialSpringVelocity: 0.6, options: UIViewAnimationOptions.curveEaseIn, animations:{
barView.center.y += (self.navigationController?.navigationBar.frame.height)!
}, completion:{ finished in
UIView.animate(withDuration: 1, delay: 1.5, usingSpringWithDamping: 0.6, initialSpringVelocity: 0.9, options: UIViewAnimationOptions.curveEaseOut, animations:{
barView.center.y -= ((self.navigationController?.navigationBar.frame.height)! + UIApplication.shared.statusBarFrame.height)
}, completion: nil)
})
}
Output from Animation 3:

Swift: Load .Xib with animation

Currently I am loading a new .Xib of class CreateAnAccount: UIView form a button pressed on another view.
At the moment it immediately switches to the Xib which is great, but is there a way of animating this? below is the code in the button.
#IBAction func createAnAccount(sender: AnyObject) {
let createAnAccountView = NSBundle.mainBundle().loadNibNamed("CreateAnAccount", owner: self, options: nil)[0] as! CreateAnAccount
createAnAccountView.frame = CGRectMake(0, 0, UIScreen.mainScreen().applicationFrame.size.width, UIScreen.mainScreen().applicationFrame.size.height + 20)
createAnAccountView.loginHandler = loginHandler
self.addSubview(createAnAccountView)
println("Create An Account Pressed")
}
Swift 4. Just place your animation code into layoutSubviews func. Works perfect for me.
override func layoutSubviews() {
super.layoutSubviews()
animate()
}
func animate() {
self.transform = CGAffineTransform(scaleX: 0.3, y: 2)
UIView.animate(withDuration: 1, delay: 0, usingSpringWithDamping: 0.3, initialSpringVelocity: 0, options: [.allowUserInteraction, .curveEaseOut], animations: {
self.transform = .identity
})
self.alpha = 1
}
Swift 5. #coldembrace answer
func animate() {
self.view.transform = CGAffineTransform(scaleX: 0.3, y: 2)
UIView.animate(withDuration: 1, delay: 0, usingSpringWithDamping: 0.3, initialSpringVelocity: 0, options: [.allowUserInteraction, .curveEaseOut], animations: {
self.view.transform = .identity
})
self.view.alpha = 1
}
You can try like this
UIView.transitionWithView(self.view, duration: 0.5, options:UIViewAnimationOptions.CurveEaseInOut,animations: {self.view.addSubview(createAnAccountView)}, completion: nil)
Moreover you change the UIViewAnimationOptions to have a desired effect.

Resources