I'm building a calculator app, when I tap on the buttons there is a short animation. The problem is the buttons do not respond while they are animating, which makes the app feel laggy.
I found some solutions for Objective-C using:
UIViewAnimationOptionAllowUserInteraction
but nothing for Swift 3, my code looks like this:
func myButton () {
sender.layer.backgroundColor = firstColor
sender.setTitleColor(UIColor.white, for: UIControlState.normal)
UIView.animate(withDuration: 0.5) {
sender.layer.backgroundColor = secondColor
}
}
Call different method of UIView:
func myButton () {
sender.layer.backgroundColor = firstColor
sender.setTitleColor(UIColor.white, for: UIControlState.normal)
UIView.animate(withDuration: 0.5,
delay: 0.0,
options: .allowUserInteraction,
animations: {
sender.layer.backgroundColor = secondColor },
completion: nil)
}
Related
By default the highlight effect of a UITableViewCell looks like this:
I'm looking for a similar effect that instead of grey is a custom color (for sake of example the UIColor default red value). I've tried to implement this myself using the setHighlighted delegate but it doesn't produce the animated effect the default style does.
This is the code I have used and the undesired effect that is achieved:
override func setHighlighted(_ highlighted: Bool, animated: Bool) {
super.setHighlighted(highlighted, animated: animated)
if highlighted {
self.backgroundColor = .red
}
}
Alongside setting cell.selectionStyle = .none in cellForRowAt.
Is there any way to produce a native-like animated custom highlight color?
You need to add another condition "else" for your "if" condition and clear the red background color to normal.
if highlighted {
self.backgroundColor = .red
}else {
self.backgroundColor = .white
}
(Edited)
You could use gestures to simulate the behaviour of the native, something like this:
let longPressRecognizer = UILongPressGestureRecognizer(target: self, action: "longPressed:")
yourCell.view.addGestureRecognizer(longPressRecognizer)
func longPressed(sender: UILongPressGestureRecognizer)
{
if sender.state == .began {
yourCell.animate(withDuration: 0.2, delay:0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEeaseOut, animations: { yourCell.backgroundColor = .red })
}
if sender.state == .ended {
yourCell.animate(withDuration: 0.2, delay:0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEeaseOut, animations: { yourCell.backgroundColor = .white })
}
}
I want the background color of my iOS app to change between four colors over x amount of seconds
This is what I have so far (it does exactly what I want when I specify just 2 colors)
I also need the animation to run in a loop infinitely.
ViewController.swift
UIView.animateWithDuration(X.0, animations: {
// Color 1
self.view.backgroundColor = UIColor(rgba)
// Color 2
self.view.backgroundColor = UIColor(rgba)
// Color 3
self.view.backgroundColor = UIColor(rgba)
// Color 4
self.view.backgroundColor = UIColor(rgba)
})
Try this out:
UIView.animateWithDuration(1.0, animations: { () -> Void in
self.view.backgroundColor = UIColor.blackColor()
}) { (Bool) -> Void in
UIView.animateWithDuration(1.0, animations: { () -> Void in
self.view.backgroundColor = UIColor.greenColor()
}, completion: { (Bool) -> Void in
UIView.animateWithDuration(1.0, animations: { () -> Void in
self.view.backgroundColor = UIColor.grayColor()
}, completion: { (Bool) -> Void in
UIView.animateWithDuration(1.0, animations: { () -> Void in
self.view.backgroundColor = UIColor.redColor()
}, completion:nil)
})
})
}
In case you want a continuous repeating animation, try this out:
UIView.animate(withDuration: 2, delay: 0.0, options:[UIView.AnimationOptions.repeat, UIView.AnimationOptions.autoreverse], animations: {
self.view.backgroundColor = UIColor.black
self.view.backgroundColor = UIColor.green
self.view.backgroundColor = UIColor.darkGray
self.view.backgroundColor = UIColor.red
}, completion: nil)
Below code helps to keep enable user interaction with animated view. A random color generation (use in case its needed).
UIView.animateWithDuration(7, delay: 1, options:
[UIViewAnimationOptions.AllowUserInteraction,
UIViewAnimationOptions.Repeat,
UIViewAnimationOptions.Autoreverse],
animations: {
self.yourView.backgroundColor = self.randomColor()
self.yourView.backgroundColor = self.randomColor()
}, completion:nil )
func randomColor() -> UIColor {
let randomRed:CGFloat = CGFloat(drand48())
let randomGreen:CGFloat = CGFloat(drand48())
let randomBlue:CGFloat = CGFloat(drand48())
return UIColor(red: randomRed, green: randomGreen, blue: randomBlue,
alpha: 1.0)
}
You have to use NSTimer:
let timer = NSTimer.scheduledTimerWithTimeInterval(5, target: self, selector: "update", userInfo: nil, repeats: true)
func update() {
let nextCollor = getNextColor()
UIView.animateWithDuration(X.0, animations: {
self.view.backgroundColor = nextCollor
})
}
func getNextColor() -> UIColor {
let currentColor = self.view.backgroundColor
if currentColor == smaple1 {
return UIColor.redColor()
} else if currentColor == smaple2 {
return UIColor.grayColor()
} else {
return UIColor.whiteColor()
}
}
NSTimer.scheduledTimerWithTimeInterval runs your code every 5 seconds
PS: do not forget invalidate timer when you done with it. Just call timer.invalidate() for it. Otherwise you get a crash.
Swift 5
override func viewWillAppear(_ animated: Bool) {
self.customButton.backgroundColor = .red
UIView.animateKeyframes(withDuration: 0.5, delay: 0, options: [.repeat, .autoreverse], animations: {
self.customButton.backgroundColor = .none
}, completion: nil)
}
i had a dynamic / unknown amount of colors to cycle through, so i refactored the Swift 5 answer a bit:
Swift 5
UIView.animate(withDuration: 1.0, delay: 0.0, options: [.repeat, .autoreverse]) {
// colors is the dynamic [UIColor] array previously defined
for color in colors {
self.colorView.backgroundColor = color
}
} completion: { (finished) in
}
this will nicely cycle through the colors with a fade-style animation -- and with the .autoreverse option, it won't "snap" to the starting color.
For some reason my animation does not run properly when I change the background of my button. I am new to animations was trying something new. I don't really need to change the background but it was how I had it in sketch and in my opinion it looks better when it is changed.
Code:
#IBAction func didTapWithUsername(sender: AnyObject)
{
// When this button is tapped the two buttons below should move down far enough to reveal
// two labels and two textboxes
// choose animation
if(userBtnTapped == 0)
{
tappedwithUserAnimationForSeperate()
userBtnTapped = 1
self.withUserNameBtn.setBackgroundImage(UIImage(named: "loginUserbtnWithFill.png"), forState: UIControlState.Normal)
}
else
{
tappedwithUserAnimationForClose()
userBtnTapped = 0
self.withUserNameBtn.setBackgroundImage(UIImage(named: "LoginWithUserbtn.png"), forState: UIControlState.Normal)
}
}
animation functions:
func tappedwithUserAnimationForSeperate()
{
UIView.animateWithDuration(1.0, delay: 0, usingSpringWithDamping: 1.0, initialSpringVelocity: 5.0, options: [], animations: ({
// code for animation goes here here
self.withUserNameBtn.center.y = self.withUserNameBtn.center.y - 60
self.withFBbtn.center.y = self.withFBbtn.center.y + 60
self.signUpBtn.center.y = self.signUpBtn.center.y + 60
}), completion: nil)
}
func tappedwithUserAnimationForClose()
{
UIView.animateWithDuration(1.0, delay: 0, usingSpringWithDamping: 1.0, initialSpringVelocity: 5.0, options: [], animations: ({
// code for animation goes here here
self.withUserNameBtn.center.y = self.withUserNameBtn.center.y + 60
self.withFBbtn.center.y = self.withFBbtn.center.y - 60
self.signUpBtn.center.y = self.signUpBtn.center.y - 60
}), completion: nil)
}
I added a custom button to the sceneKit view. When it is touched, it plays an animation, indicating that it was clicked. The problem I'm facing is the delay between user touch and start of animation. My scene has 28.1K triangles and 84.4K vertices. Is that to much or do I need to implement buttons differently. The scene renders with 60fps. I added the button via sceneView.addSubview: Thanks for answers
viewDidLoad(){
// relevant code
starButton = UIButton(type: UIButtonType.Custom)
starButton.frame = CGRectMake(100, 100, 50, 50)
starButton.setImage(UIImage(named: "yellowstar.png"), forState: UIControlState.Normal)
sceneView.addSubview(starButton)
starButton.addTarget(self, action: "starButtonClicked", forControlEvents: UIControlEvents.TouchUpInside)
starButton.adjustsImageWhenHighlighted = false
}
func starButtonClicked(){
animateScaleDown()
}
func animateScaleDown(){
UIView.animateWithDuration(0.1, animations: {
self.starButton.transform = CGAffineTransformMakeScale(0.8, 0.8)
}, completion: { _ in
self.wait()
})
}
func wait(){
UIView.animateWithDuration(0.2, animations: {}, completion: { _ in
UIView.animateWithDuration(0.2, animations: {
self.starButton.transform = CGAffineTransformMakeScale(1, 1)
})
})
}
Okay I solved it. The problematic piece of code is
starButton.addTarget(self, action: "starButtonClicked", forControlEvents: UIControlEvents.TouchUpInside)
UIControlEvent.TouchUpInside gives the illusion of lag. Changing it to .TouchDown is much better.
For Swift 5
var starButton = UIButton()
func a () {
starButton = UIButton(type: UIButton.ButtonType.custom)
starButton.frame = CGRect(x: 100, y: 100, width: 50, height: 50)
starButton.backgroundColor = .blue
SpielFenster.addSubview(starButton)
starButton.addTarget(self, action: #selector(starButtonClicked), for: UIControl.Event.touchDown)
starButton.adjustsImageWhenHighlighted = false
}
#objc func starButtonClicked(){
animateScaleDown()
}
func animateScaleDown(){
UIView.animate(withDuration: 0.1, animations: {
self.starButton.transform = CGAffineTransform(scaleX: 0.8, y: 0.8)
}, completion: { _ in
self.wait()
})
}
func wait(){
UIView.animate(withDuration: 0.2, animations: {}, completion: { _ in
UIView.animate(withDuration: 0.2, animations: {
self.starButton.transform = CGAffineTransform(scaleX: 1, y: 1)
})
})
}
i'm working on a UIButton animation where it moves along x-axis while it scales to its original size from the initial size. when i tried the code below it doesnt move to the point where it should go and doesn't scale up to its original size.
this is my code for initializing the button:
_testBtn1.layer.anchorPoint = CGPointMake(0.5f, 0.5f);
scaleBtn = CGAffineTransformMakeScale(0.2, 0.2);
[_testBtn1 setTransform: scaleBtn];
and this is my code for the moving/translation and scaling:
CGAffineTransform translate = CGAffineTransformMakeTranslation(50.0f, 0.0f);
CGAffineTransform animate = CGAffineTransformConcat(scaleBtn, translate);
[_testBtn1 setTransform:animate];
any help, suggestion, advice will be appreciated. i'm new to iOS..thanks!
You can just create a custom type UIButton (either with IB by changing the type to Custom, or programmatically with
UIButton *aButton = [UIButton buttonWithType:UIButtonTypeCustom];//set the button's image with
[aButton setImage:[UIImage imageNamed:#"abc" forState:UIControlStateNormal];
To move it, just animate its position normally...
[UIView animateWithDuration:0.5 animations:^{aButton.center = newCenter;}];
Or
CGRect originalFrame = aButton.frame;
aButton.frame = CGRectMake(originalFrame.origin.x, originalFrame.origin.y, originalFrame.size.width, 0);
[UIView animateWithDuration:0.5 animations:^{aButton.frame = originalFrame;}];
OR Reffer this link
http://objectiveapple.blogspot.in/2011/10/23-quizapp-16-animate-scale-uibutton.html
This should be easily done with Core Animation, take a look the the most basic one CABasicAnimation
A simple scale(bouncy) animation with completion handler implementation in swift.
Hope it'll help you or anyone else in some way.
viewToanimate.transform = CGAffineTransform(scaleX: 0.1, y: 0.1)
UIView.animate(withDuration: 0.7,
delay: 0,
usingSpringWithDamping: 0.2,
initialSpringVelocity: 6.0,
animations: { _ in
viewToAnimate.transform = .identity
},
completion: { _ in
//Implement your awesome logic here.
})
I made this animation:
With this reusable class:
class AnimatedButton: UIButton {
override init(frame: CGRect) {
super.init(frame: frame)
addTargets()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
addTargets()
}
func addTargets() {
self.addTarget(self, action: #selector(scaleDownAnimated), for: .touchDown)
self.addTarget(self, action: #selector(scaleBackToNormalAnimated), for: [.touchUpOutside, .touchCancel, .touchUpInside])
}
#objc func scaleDownAnimated() {
UIView.animate(withDuration: 0.25, delay: 0, options: .allowUserInteraction) {
self.transform = CGAffineTransform(scaleX: 0.8, y: 0.8)
} completion: { _ in }
}
#objc func scaleBackToNormalAnimated() {
UIView.animate(withDuration: 0.2, delay: 0, options: .allowUserInteraction) {
self.transform = CGAffineTransform(scaleX: 1, y: 1)
} completion: { _ in }
}
}
Then just make the class of your button AnimatedButton like below (if you are using Storyboards) and use the button normally: