UIButton resize animation is not animating - swift

I'm trying to make that my button double its size using the UIView animation, but for some reason it is not working it the size goes right, but no animated.
The function that should animate the button resizing
Irrelevant code above
#objc func createButtonPressed(){
//Removes the bottom stack with buttons
if let stackButton = self.view.viewWithTag(50){
stackButton.removeFromSuperview()
}
//Add the button back with half ares size
bottomHolder.addSubview(rightButton)
rightButton.setImage(nil, for: .normal)
rightButton.addTarget(self, action: #selector(anima), for: .touchUpInside)
rightButton.topAnchor.constraint(equalTo: bottomHolder.topAnchor).isActive = true
rightButton.trailingAnchor.constraint(equalTo: bottomHolder.trailingAnchor).isActive = true
rightButton.bottomAnchor.constraint(equalTo: bottomHolder.bottomAnchor).isActive = true
}
#objc func anima(){
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: {
self.rightButton.leadingAnchor.constraint(equalTo: self.bottomHolder.leadingAnchor).isActive = true
self.rightButton.layoutIfNeeded()
}, completion: nil)
}
Irrelevant code below

try this one:
let buttonFinalWidth = UIScreen.main.bounds.width
DispatchQueue.main.async {
UIView.animate(withDuration: 5.0) {
self.rightButton.widthAnchor.constraint(equalToConstant: buttonFinalWidth).isActive = true
self.view.layoutIfNeeded()
}
}

Related

Constraint animation doesnt animate y position change

This code is to expand a label by disabling the constraint which is keeping it at a max height of 54 to a full size. It works as it should but it jumps to the new y position straight away (without animating) and changes frame height after which makes it look like it jumps before animating
#IBOutlet var descriptionHeightConstraint: NSLayoutConstraint!
#IBAction func toggleFullDescription(_ sender: Any) {
if descriptionHeightConstraint.isActive {
self.layoutIfNeeded()
descriptionHeightConstraint.isActive = false
UIView.animate(withDuration: 0.3, delay: 0, options: .curveEaseInOut, animations: {
self.layoutIfNeeded()
}, completion: nil)
//seeMoreButton.setTitle("See less", for: .normal)
} else {
self.layoutIfNeeded()
descriptionHeightConstraint.isActive = true
UIView.animate(withDuration: 0.3, delay: 0, options: .curveEaseInOut, animations: {
self.layoutIfNeeded()
}, completion: nil)
//seeMoreButton.setTitle("See more", for: .normal)
}
}
Video of the issue

UI Animation using animateKeyframes does nothing to Button Title Color

I'm trying to animate the color of my UIButton Title Color using animateKeyframes but it does nothing except load the last state in the animation, in this case purpleText. I'm using the same code to animate button colors and a UIView background color without any issues.
I checked also changed the button to a custom button in Interface Builder but that didn't help either.
UIView.animateKeyframes(withDuration: 12, delay: 12, options: [.allowUserInteraction, .repeat, .autoreverse], animations: {
UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 0.25, animations: {
self.infoButton.setTitleColor(blueText, for: UIControlState.normal)
})
UIView.addKeyframe(withRelativeStartTime: 0.2, relativeDuration: 0.25, animations: {
self.infoButton.setTitleColor(greenText, for: UIControlState.normal)
})
UIView.addKeyframe(withRelativeStartTime: 0.4, relativeDuration: 0.25, animations: {
self.infoButton.setTitleColor(yellowText, for: UIControlState.normal)
})
UIView.addKeyframe(withRelativeStartTime: 0.6, relativeDuration: 0.25, animations: {
self.infoButton.setTitleColor(redText, for: UIControlState.normal)
})
UIView.addKeyframe(withRelativeStartTime: 0.8, relativeDuration: 0.25, animations: {
self.infoButton.setTitleColor(purpleText, for: UIControlState.normal)
})
}, completion: nil)
Calling setTitleColor() inside the animation block doesn't work because UIView.animate only works on animatable properties, like infoButton.backgroundColor.
Unfortunately, button properties like tintColor aren't animatable. You also shouldn't directly access the button's titleLabel, which is nil for system buttons.
Instead, you can use UIView.transition with setTitleColor(). You can then put it inside a Timer... I usually don't like to use timers for animations, but I can't think of any other way.
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let colors: [UIColor] = [.blue, .green, .yellow, .red, .purple]
var currentIndex = 0
_ = Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true) { timer in
if colors.indices.contains(currentIndex) {
UIView.transition(with: self.infoButton, duration: 0.5, options: [.transitionCrossDissolve, .allowUserInteraction]) {
self.infoButton.setTitleColor(colors[currentIndex], for: .normal)
}
currentIndex += 1
} else {
currentIndex = 0
}
}
}
Result:

UIButton Animations not working on UIScrollView

I have button animations that are not working on my ScrollView. I have other VCs that are just UIViews and animations work just fine.
So I tried unchecking from the Attributes Inspector and adding...
self.scrollView.delaysContentTouches = false
...in my viewDidLoad, but it had effect.
I also found that tapping does not trigger the animation but holding on the button for a second or more does and haptic presses also trigger the animation.
This is my animation code:
extension UIButton {
func startAnimatingPressActions() {
addTarget(self, action: #selector(animateDown), for: [.touchDown, .touchDragEnter])
addTarget(self, action: #selector(animateUp), for: [.touchDragExit, .touchCancel, .touchUpInside, .touchUpOutside])
}
#objc private func animateDown(sender: UIButton) {
animate(sender, transform: CGAffineTransform.identity.scaledBy(x: 0.95, y: 0.95))
}
#objc private func animateUp(sender: UIButton) {
animate(sender, transform: .identity)
}
private func animate(_ button: UIButton, transform: CGAffineTransform) {
UIView.animate(withDuration: 0.4,
delay: 0,
usingSpringWithDamping: 0.5,
initialSpringVelocity: 3,
options: [.curveEaseInOut],
animations: {
button.transform = transform
}, completion: nil)
}
}
I am able to get this animation working, but it doesn't feel quite right. So I'd rather not use the code below. But it does work. So I'm not sure what in the code above is causing the problem.
extension UIButton {
func pulsate() {
let pulse = CASpringAnimation(keyPath: "transform.scale")
pulse.duration = 0.2
pulse.fromValue = 0.96
pulse.toValue = 1.0
pulse.repeatCount = 0
pulse.initialVelocity = 0.5
pulse.damping = 1.0
layer.add(pulse, forKey: nil)
}
}
I had the same issue and I solved unchecking the delay touch down button in the scrollview's attributes inspector :
ScrollView's attrobutes inspector

Trying change Button Title and label.center.x in UIView.animate when press button but stuck. Why? Swift 4 Xcode 9.4

My Problem
I'm trying do some animation with label using UIView.animate(..) when touchInside button . Everything still be OK until I added a line: "self?.confirm.setTitle("Đăng nhập", for: .normal). The animation doesn't work.
My Will
I want the yellow underline below Đăng Ký switch to below Đăng nhập.
It good when code is
#IBAction func signUpAction(_ sender:Any?){
if (signup == false){
signup = true
UIView.animate(withDuration: 0.4, delay: 0, options: [.curveEaseIn], animations: {[weak self] in
self?.underlineSignup.center.x -= (self?.underlineSignup.bounds.width)!
self?.view.layoutIfNeeded()
}, completion: nil)
}
}
#IBAction func signInAction(_ sender:Any?){
if (signup == true){
signup = false
UIView.animate(withDuration: 0.4, delay: 0, options: [.curveEaseIn], animations: {[weak self] in
self?.underlineSignup.center.x += (self?.underlineSignup.bounds.width)!
self?.view.layoutIfNeeded()
}, completion: nil)
}
}
It work
But when I add .setTitle
#IBAction func signUpAction(_ sender:Any?){
if (signup == false){
signup = true
UIView.animate(withDuration: 0.4, delay: 0, options: [.curveEaseIn], animations: {[weak self] in
self?.underlineSignup.center.x -= (self?.underlineSignup.bounds.width)!
self?.confirm.setTitle("Đăng ký", for: .normal)
self?.view.layoutIfNeeded()
}, completion: nil)
}
}
#IBAction func signInAction(_ sender:Any?){
if (signup == true){
signup = false
UIView.animate(withDuration: 0.4, delay: 0, options: [.curveEaseIn], animations: {[weak self] in
self?.underlineSignup.center.x += (self?.underlineSignup.bounds.width)!
self?.confirm.setTitle("Đăng nhập", for: .normal)
self?.view.layoutIfNeeded()
}, completion: nil)
}
}
It stuck, only the title of button confirm change, the underline doesn't move
Please anyone can explain this situation.
EDIT:
The animation working but it's destination is always the first place which under Đăng ký ( animation come from left or right of it, the result always first place )
I think I knew how it is. Because in setTitle has updateFrame Constraintlayout of view. I have a contraintlayout when build button.
When I setTitles it reset the view using constraint.
That's what I think about this.
Try putting 'setTitle' into completion.
UIView.animate(withDuration: 0.15, delay: 0, options: .curveLinear, animations: {
self?.underlineSignup.center.x -= (self?.underlineSignup.bounds.width)!
self?.view.layoutIfNeeded()
}){
//completion
self?.confirm.setTitle("Đăng ký", for: .normal)
}

How to add transition on UITapGestureRecognizer in Swift 3?

I'm trying to make the image view full screen when I click on the small image. But the image show very fast when I clicked on the image. Can I add some transition time to delay the full screen image showing?
#IBAction func uploadImgAction(_ sender: Any) {
let tapgesture = UITapGestureRecognizer(target: self, action: #selector(DeleteJobViewController.tap))
tapgesture.numberOfTapsRequired = 1
reasonImg.addGestureRecognizer(tapgesture)
}
func tap(){
print("tap")
let newImageView = UIImageView(image: reasonImg.image)
newImageView.frame = self.view.frame
newImageView.backgroundColor = .black
newImageView.contentMode = .scaleAspectFit
newImageView.isUserInteractionEnabled = true
let tap = UITapGestureRecognizer(target: self, action: #selector(dismissFullscreenImage))
newImageView.addGestureRecognizer(tap)
self.view.addSubview(newImageView)
}
func dismissFullscreenImage(sender: UITapGestureRecognizer) {
sender.view?.alpha = 1
UIView.animate(withDuration: 1.5, animations: {
sender.view?.alpha = 0
sender.view?.removeFromSuperview()
})
}
Try replacing the self.view.addSubview(newImageView) line with:
DispatchQueue.main.async {
UIView.transition(with: self.view, duration:0.6, options: UIViewAnimationOptions.showHideTransitionViews, animations: {
self.view.addSubview(self.newImageView)
}, completion: nil)
}
You can also try setting newImageView.alpha = 0 before running this code:
UIView.animate(withDuration: 1.5, animations: {
self.newImageView.alpha = 1.0
})
For animating the disappear effect, in the code above, replace the addSubview statement with newImageView.removeFromSuperview().
And similarly you can set this after you have set the newImageView.alpha = 1:
func dismissFullscreenImage(sender: UITapGestureRecognizer) {
UIView.animate(withDuration: 1.5, animations: {
self.newImageView.alpha = 0
})
}
EDIT:
Please add newImageView as a property at the top of your view controller.
Then in your tap function set this instead of let newImageView:
self.newImageView = UIImageView(image: reasonImg.image)
Now if you run the code it should compile.
yourImageView.alpha = 0
*your addSubview in the middle
UIView.animate(withDuration: 0.5, animations: {
yourImageView.alpha = 1
})
First set your image to be invisible, then animate (in my example for 0.5 sec) to be visible.
func tap() {
print("tap")
let newImageView = UIImageView(image: reasonImg.image)
newImageView.frame = self.view.frame
newImageView.transform = CGAffineTransform.init(scaleX: 0.0, y: 0.0)
newImageView.backgroundColor = .black
newImageView.contentMode = .scaleAspectFit
newImageView.isUserInteractionEnabled = true
let tap = UITapGestureRecognizer(target: self, action: #selector(dismissFullscreenImage))
newImageView.addGestureRecognizer(tap)
self.view.addSubview(newImageView)
UIView.animate(withDuration: 0.5, animations: {
newImageView.transform = CGAffineTransform.init(scaleX: 1.0, y: 1.0)
})
}