UiView.animateWithDuration Not Animating Swift - ios

I am trying to animate show/hide of search bar using below code (The search bar should come from left and expand to right within 1-2 seconds). However, it doesn't animate and searchBar is immediately shown no matter how much time I put. I noticed following:
Duration is not respected
Not even delay is respected
Animation is not happening. Component is immediately shown
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
//code to get selected value...
//Hide the collection view and show search bar
UIView.animateWithDuration(10.0,
delay: 0.0,
options: UIViewAnimationOptions.TransitionCrossDissolve,
animations: {
self.searchBar.hidden = false
self.searchBar.frame = CGRectMake(0, 0, 300, 44) //This doesn't work either
},
completion: { (finished: Bool) in
return true
})
}
I am using Xcode 7, iOS 8 and Swift 2.0. I have seen at other solution, but none of them works for me. Kindly help...
Update: It worked with below code. However, it used default animation option of UIViewAnimationOptionCurveEaseInOut and TransitionNone
UIView.animateWithDuration(0.7,
animations: {
self.searchBar.alpha = 1.0
self.searchBarRect.origin.x = self.searchBarRect.origin.x + 200
self.searchBar.frame = self.searchBarRect
},
completion: { (finished: Bool) in
return true
})

Before the animateWithDuration, set the XPosition to -200 and YPosition to -200.
Like Daniel Suggested, you need to also change the alpha from something other than 1.0 in order to see it "fade in".
Are you using autolayout? If you are, you may want to animate the constraints instead of the frame.
Finally, are you sure you've wired up the search bar properly?
Edit: PS, I would keep the duration to something like 3.0 or 5.0. 10.0 will take forever and may make you think that it isn't doing anything because of how long it takes. Make it 3.0 or 5.0 (max) just for testing and then decrease to where you want it.

Related

UIview animation misbehaves when image of an unrelated button is changed

On my viewcontroller, I have a button to enable/disable audio using the following action:
func audioControl() {
playMusic = playMusic ? false : true // toggle
if (playMusic) {
startMusic()
audioBtn.setImage(UIImage(named: "musicOn"),for: .normal)
}
else {
stopMusic()
audioBtn.setImage(UIImage(named: "musicOff"),for: .normal)
}
}
The button toggles its image, as expected.
There is also an unrelated UIImageView object on the same VC which is being translated as follows:
UIView.animate(withDuration: 10.0, delay: 0.0, options: [ .curveLinear, .repeat ], animations: {
self.movingImg.center = CGPoint(x: screenSize.minX, y: screenSize.maxY)
})
This simple animation works fine by itself. However, as soon as the button is tapped, the movingImg object goes outside the boundary of screen and it is no longer visible.
I am not sure why a change of image on a button causes another object animation to misbehave. Any thoughts? I am using Swift 3.
Thank you.
After reading through discussions in a number of SO threads, I found that with the image change (along with any other layout changes), the viewcontroller's viewDidLayoutSubviews() gets called. As such, the followings are two things I did to resolve this issue:
Within the audioControl() method, I removed the animation of movingImg (i.e. movingImg.layer.removeAllAnimations()) before updating the button image.
I added viewDidLayoutSubviews() to my viewcontroller and started the animation of movingImg there.
Hopefully, this approach helps others too.

Animate an imageView with changing constraints (progress bar) Swift

So, I am creating a sort of progress bar, mostly just an animation to go from 0 to 100 percent. I have two images, one that is red on bottom, one on top that is black. I am trying to take away from the top image to create the idea that it is loading from 0 to 100%, slowly revealing the image below. I have all of that working, my problem is that I do not see the in between. I see 0% and 100%, I can debug it and view the controller and see my view controller (self) updating and slowly taking away the top image so I know that it is working but I do not see it go through each animate. I have edited one moved things around a ton but have not been able to see the changes. Thanks for everyones help in advance!
override func viewDidAppear(_ animated: Bool) {
if intCounter <= 100{
UIView.animate(withDuration: 0.05, animations: catScanE.layoutIfNeeded)
repeat {
dblImageH = dblImageH - 3.80
self.catScanE.frame = CGRect(x: 27 , y: 197, width: 320, height: dblImageH)
intCounter = intCounter + 1
} while (intCounter <= 100)
} else {
performSegue(withIdentifier: "lastSegue", sender: nil)
}
}
I have gotten the animate to basically work, it scrolls down the screen but shows a type of animation. I want it to slowly restrict the constraints but this is not the issue now. Since the animation "works", I am not able to get it to segue after the animation, this is what I have. Adding the if intCounter part makes it skip the animation and segue, without it the screen performs the animation and sits there...
override func viewDidAppear(_ animated: Bool) {
UIView.animate(withDuration: 5.0, animations: {
self.dblImageH = self.dblImageH - 3.80
self.catScanE.frame = CGRect(x: 27 , y: 197, width: 320, height: self.dblImageH)
self.intCounter = self.intCounter + 1
if self.intCounter > 100{
self.performSegue(withIdentifier: "lastSegue", sender: nil)}
})
}
I figured it out with some help from Ravron and more StackOverflow searching. I set the content mode to top in the attributes and used this code to make it act like a progress bar (this is a black image with a red one underneath to look like it is going from 0 to 100). I ran into an issue with the image basically moving up or downwards, this was fixed by changing the y coordinate to match the change in size so it would basically stay in the same position. I just need to figure out how to make a counter to go from 0 to 100 while it is animating. Thanks! Hopefully this can help someone else making a custom progress bar.
override func viewDidAppear(_ animated: Bool) {
UIView.animate(withDuration: 5.0, animations: {
self.catScanE.frame = CGRect(x: 27 , y: 200, width: 320, height: 0)
}, completion: {finished in self.performSegue(withIdentifier: "lastSegue", sender: nil)})
}
Your animate block runs only once, and the final settings of the view's frame is all that counts. The view is actually being animated from 0% to 100% as you wish, but it happens in 50 milliseconds, or about three frames.
Just set the frame to the desired final position in the animate block and increase the duration to something reasonable, like 100 * 0.05s = 5s.
To expand slightly: the animate method says, informally, "run the block below, which changes one or more traits of various views. Then, implicitly animate those traits from their current values to the values set when the block was run." So it's only called once, and in it you should set traits to their desired final values.
Consider reading through the animations section of the View Programming Guide for iOS which gives a comprehensive overview of animation basics on the platform, and also covers UIView block-based animations, the type you're trying to use here.

Not all content is animated inside a stack view when hiding it

I'm currently working on a iOS (swift 3) app. I have a simple vertical stack view containing 2 horizontal stack views. In some cases I want to hide the bottom one. I do so by using the following code
UIView.animate(withDuration: 3) {
self.bottomStackView.isHidden = true;
};
The animation shown below doesn't really do what I would expect:
While the border of the buttons is animated properly when hiding, the text inside each button doesn't seem to be affected until the very end. Any idea as to how I could fix this?
I kept doing some research on the subject, and it seems like most articles were suggesting that using stacks to perform animation would work fine. However I have also found that animations would only work with animatable properties, isHidden not being one of them.
In the end after some trial and errors I have found that isHidden can be animated with stack views, but you can expect children to misbehave. So far the only workaround I have found is like so:
let duration = 0.5;
let delay = 0;
UIView.animate(withDuration: duration, delay: delay, animations: {
self.bottomStack.isHidden = self.hideBottomStack;
})
UIView.animate(withDuration: duration/2, delay: delay, animations: {
self.bottomStack.alpha = 0;
})
You'll note here that I basically "turn" the alpha property down to 0 in half the time I take to hide the stack. This has the effect to hide the text before it overlaps with the upper stack. Also note that I could also have decided to do something like this:
UIView.animate(withDuration: duration, delay: delay, animations: {
self.bottomStack.alpha = 0;
}, completion: { (_) in
self.bottomStack.isHidden = true;
})
This would also hide the bottom stack, but you lose the hiding motion in favor of a fading motion and hide the stack once the fading is done.
I'm not sure about this, I think stackviews can cause weird behaviour sometimes. Have you tried adding "self.view.layoutIfNeeded()" inside the UIView.animate block? Like this:
UIView.animate(withDuration: 3) {
self.bottomStackView.isHidden = true
self.view.layoutIfNeeded()
}
I think it should also work if you put the "self.bottomStackView.isHidden = true" above the UIView.animate, not sure though, not an expert at it.
Also, I don't think you need to use ";" after your line of code in swift :)

swift 3 layoutIfneeded not working properly

To make proper animation of a uiview with constraints u must set the new constraint value and then call theView.layoutIfNeeded() , for swift 3 this doesnt work and instead of calling from the view's whos constraint is changed . it must be called from the upper view like this : self.view.layoutIfNeeded().
ex :
UIView.animate(withDuration: 0.1,
delay: 0.1,
options: UIViewAnimationOptions.curveEaseIn,
animations: { () -> Void in
constraintHeight.constant = 10.00
// instead of myView.layoutIfNeeded() // Swift 2
self.view.layoutIfNeeded() // Swift 3
}, completion: { (finished) -> Void in
// ....
})
The problem is, in my case i did the change and the way im using this animation is for a bottomview (a bottom bar/ banner view) that hides when scrolling a tableview down and comes up when going all the way to the top in the tableview. now that i have changed the proper code for swift 3 using self.view.layoutIfNeeded() , the tableview acts wierd, slows down, rows start appearing as fading in or is just way slow to present, when scrolling down and up the tableview's sections comes jumping or moving in slow motion, also have seem memory gone up from 80mb to 100mb . if i eliminate the line in the code, i dont get the animation, the view just appears and dissapears with the scrolling of the tableview, but... i dont get the strange behavior. i have also checked the views hierarchy to check somehow is not creating wierd 100 views replicating or something.. any hints on how can i fix this . all of this was just working fine in swift 2 using theView.layoutIfneeded() but now that the call is being madein the upper view.. omg..wierd acting
Question comes from Swift 3 UIView animation solution.
Try this to force layout changes to superview
//Force to complete all changes.
self.view.superview.layoutIfNeeded()
//Update constant
constraintHeight.constant = 10.00
UIView.animate(withDuration: 0.1,
delay: 0.1,
options: UIViewAnimationOptions.curveEaseIn,
animations: { () -> Void in
self.view.superview.layoutIfNeeded()
}, completion: { (finished) -> Void in
// ....
})
Solution to my needs . thanks all for sharing your answers!.
my view hierarchy
- root view
- uitableView
- bottomBarView
- bottomBannerView
Beacause of that hierarchy i couldnt use self.view.layoutIfNeeded() or self.bottomBarView.superview?.layoutIfneeded(), as it was calling to layout the same superview which also host the tableview and for which im triggering this function if scrolling is more than 10 and also if it less.. so its always trigerring the layoufIfneededmethod. i had to do what i thought from the beginning.
The correct way is to make a container view hosting the bottombarview and the banner view, have it constraint to bottom of the root super view and constraint the bottomBarView and bottomBannerView to IT.
View hierarchy now is .
-root view
-uitableView
-containerBottomView
-bottomBarView
-bottomBannerView
This way i can call self.bottomBarView.superview?.layoutIfNeeded() , and it wont be triggering on the root view which also host the uitableview. it correctly triggers to layout the containerBottomView.
UIView.animate(withDuration: 0.5, delay: 0.3, options: [.repeat, .curveEaseOut, .autoreverse], animations: {
// perform your animation here .
self.username.center.x += self.view.bounds.width
self.view.layoutIfNeeded()
}, completion: nil)

Replicate iOS 8.4 music app search animation

I am making an app with a search button in the nav bar. I would like to replicate the search animation in the music app.
I would like to press search and have the search bar come in from the top, and the table view to fade in.
Is there an easy way to do this?
I believe its pretty simple
It is actually a different view that is sliding down.
So essentially create a view with everything you want on it. Like the textField, the cancel button, etc.
This view when it is created needs to appear above your mainView.
So the y value on your frame will be 0 minus your new view height.
When you are ready for the view to appear use UIView.animateWithDuration to change your views frame y value to 0
UIView.animateWithDuration(2, delay: 0.0, options: UIViewAnimationOptions.CurveLinear, animations: {
myView.frame = CGRectMake(0, myView.frame.origin.y + myView.frame.height, 100, 100)
//could also just set the y value to 0 but I included the origin/height part to help you understand
}, completion: {
(value: Bool) in
})

Resources