User interaction with uiview and animation completion blocks - iphone

I have the following code:
[UIView animateWithDuration:2.0 delay:0.0 options:UIViewAnimationOptionAllowUserInteraction
animations:^{
imageView.bounds = endBounds;
}
completion:^(BOOL finished) {
[UIView animateWithDuration:2.0 delay:0.5 options:UIViewAnimationOptionAllowUserInteraction
animations:^{
imageView.bounds = startBounds;
}
completion:^(BOOL finished) {
[imageView removeFromSuperview];
}];
}];
Additionally I have:
[imageView setUserInteractionEnabled:YES];
and a tap gesture recognizer set that will handle the user tapping on imageView. While the first animation is happening, the gesture recognizer fires as I would expect. But if I try and tap imageView during the chained animation from the completion block, nothing happens even though I have set the appropriate option.
Anyone have any thoughts? I've googled and can't find an answer.

When using the new animation blocks, if you want user interaction to be enabled during the animation, you have to set it in the options mask. For example:
[UIView animateWithDuration:1.0
delay:0
options:UIViewAnimationOptionAllowUserInteraction
animations:^{ myView.alpha = 0.5; }
completion:NULL];

I came up with a solution:
I wrap the UIImageView in a UIView (I subclass UIView) with the same bounds/center point as the image. Then I attach the gesture recognizer to the wrapper, instead of the image. Because the wrapper's bounds rectangle/center point never change for the duration of the animation, it's always available as the target of a gesture.
This works quite well.
-j

Do you see the same behaviour if you use:
+ [UIView setAnimationDidStopSelector:]
instead of using blocks?

Related

xcode - make searchbar appear/disappear

I my mapview app, I have a search bar used to search a concrete address.
It works bur for now, it appear in "static" way above the map.
My idea is make that it appear and disapperar using a button "search" as in the picture:
Any idea about hoy do thath?
Thanks in advance
You can do this in code. All you have to do is change its frame.
Add it to your navigationBar.frame and below it and then, when the icon is tapped, put it down. I usually use this code to make it look nice too:
[UIView animateWithDuration:0.2f delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
//Move it down here by changing its .frame
}completion:^(BOOL finished){
}];
You just Need To change the Frame of UISearchBar as You click search Icon to display it.
See
Initially,When You don't to display UISearchBar You should set the Frame In such manner.
initially set The Frame of UISearchBar Out Side The ViewFrame.
thisSearchBar.frame = CGRectMake(0.0, -50.0, searchBarWidth, searchBarHeight)]; in viewDidLoad method
On clicking the Search Icon to display the UISearchBar
- (void)showSearchBar{
[UIView animateWithDuration:0.2f delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
thisSearchBar.frame = CGRectMake(0.0, 50, searchBarWidth, searchBarHeight)];
}completion:^(BOOL finished)
{
}];
}
And You finished Work With SearchBar Again Call Set The Frame of Searchbar with ANimation
- (void)hideSearchBar{
[UIView animateWithDuration:0.2f delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
thisSearchBar.frame = CGRectMake(0.0, -50, searchBarWidth, searchBarHeight)];
}completion:^(BOOL finished)
{
}];
}
Per my comment, simply use:
searchBar.hidden = true;

How to cancel UIView block-based animation?

I've searched loads of SO stuff and in Apple's references, but still unable to manage my problem.
What I have:
A screen with 2 UIImageViews and 2 UIButtons connected to them
2 kinds of animation:
Scaling up and then down of each image, one after another, only once in viewDidLoad
When a button pressed (a custom button hidden 'inside' of each UIImageView) it triggers animation of appropriate UIImageView–only one, not both–(also scale up, then down).
As I am writing for iOS4+ I'm told to use block based animations!
What I need:
How do I cancel a running animation? I've managed to cancel after all but the last one... :/
Here is my code snippet:
[UIImageView animateWithDuration:2.0
delay:0.1
options:UIViewAnimationOptionAllowUserInteraction
animations:^{
isAnimating = YES;
self.bigLetter.transform = CGAffineTransformScale(self.bigLetter.transform, 2.0, 2.0);
} completion:^(BOOL finished){
if(! finished) return;
[UIImageView animateWithDuration:2.0
delay:0.0
options:UIViewAnimationOptionAllowUserInteraction
animations:^{
self.bigLetter.transform = CGAffineTransformScale(self.bigLetter.transform, 0.5, 0.5);
} completion:^(BOOL finished){
if(! finished) return;
[UIImageView animateWithDuration:2.0
delay:0.0
options:UIViewAnimationOptionAllowUserInteraction
animations:^{
self.smallLetter.transform = CGAffineTransformScale(self.smallLetter.transform, 2.0, 2.0);
} completion:^(BOOL finished){
if(! finished) return;
[UIImageView animateWithDuration:2.0
delay:0.0
options:UIViewAnimationOptionAllowUserInteraction
animations:^{
self.smallLetter.transform = CGAffineTransformScale(self.smallLetter.transform, 0.5, 0.5);
}
completion:^(BOOL finished){
if (!finished) return;
//block letter buttons
[self.bigLetterButton setUserInteractionEnabled:YES];
[self.smallLetterButton setUserInteractionEnabled:YES];
//NSLog(#"vieDidLoad animations finished");
}];
}];
}];
}];
Somehow the smallLetter UIImageView is not working properly, because when pressed (through button) bigLetter is canceling animations properly...
EDIT:
I've used this solution, but still having problem with scaling down smallLetter UIImageView - not cancelling at all...
solution
EDIT2: I've added this at the beginning of next/prev methods:
- (void)stopAnimation:(UIImageView*)source {
[UIView animateWithDuration:0.01
delay:0.0
options:(UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionAllowUserInteraction)
animations:^ {
source.transform = CGAffineTransformIdentity;
}
completion:NULL
];
}
problem stays... :/ no idea how to interrupt last animation for letters in animation chain
You can stop all animations on a view by calling:
[view.layer removeAllAnimations];
(You'll need to import the QuartzCore framework to call methods on view.layer).
If you want to stop a specific animation, not all animations, your best best bet is to use CAAnimations explicitly rather than the UIView animation helper methods, then you will have more granular control and can stop animations explicitly by name.
The Apple Core Animation documentation can be found here:
https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CoreAnimation_guide/CreatingBasicAnimations/CreatingBasicAnimations.html
For iOS 10 use UIViewPropertyAnimator to animate.
It provides methods to start, stop and pause UIView animations.
let animator = UIViewPropertyAnimator(duration: 2.0, curve: .easeOut){
     self.view.alpha = 0.0
}
// Call this to start animation.
animator.startAnimation()
// Call this to stop animation.
animator.stopAnimation(true)
I'd add to Nick's answer that to make removeAllAnimations smooth next idea be very handy.
[view.layer removeAllAnimations];
[UIView transitionWithView:self.redView
duration:1.0f options:UIViewAnimationOptionTransitionCrossDissolve animations:^{
[view.layer displayIfNeeded];
} completion:nil];
You can try this (in Swift):
UIView.setAnimationsEnabled(false)
UIView.setAnimationsEnabled(true)
Note: you can put code between those two calls if necessary, for example:
UIView.setAnimationsEnabled(false)
aview.layer.removeAllAnimations() // remove layer based animations e.g. aview.layer.opacity
UIView.setAnimationsEnabled(true)

How do I start an animation without canceling touches?

I have a UIView nested in a UIView. When I animate the frame and alpha of the inner view, touches in the outer view get canceled. Can I stop that from happening?
You can use block based animation methods.
[UIView animateWithDuration:1.0
delay:0.0
options:UIViewAnimationOptionAllowUserInteraction
| UIViewAnimationOptionCurveEaseInOut
animations:^{
//your animation code
} completion:^(BOOL finished){
//your code when animation finished..
}];

UIViews not animating when changing between each other

I have 2 views which are the same size, with colourPreview set as a subview of self.view. This is my code for showing the animation:
-(void)startEditingHexLabel {
[UIView animateWithDuration:0.3
animations:^{
[UIView setAnimationTransition:UIViewAnimationTransitionCurlDown forView:hexTextView cache:YES];
[colourPreview removeFromSuperview];
[self.view addSubview:hexTextView];
[self.view sendSubviewToBack:colourPreview];
}
completion:^(BOOL finished){
[hexText becomeFirstResponder];
}];
}
But it just changes to the new view without a transition. Any ideas?
Have you tried using transitionWithView:duration:options:animations:completion: (docs here). Seems this is preferred in iOS 4.0+. There's an example of how to use it in those docs.
If you want to use your current method, I think forView in [UIView setAnimationTransition:forView:cache:] needs to be the superview of the views you want to animate. In your case, this looks to be self.view. Full docs here.
HTH

UIView block animation with completion handler and setting UIViews to hidden

I'm keen on the new block animations in iOS 4. That is, the syntax
[UIView animateWithDuration:.25 delay:0 options:UIViewAnimationOptionAllowUserInteraction animations:^
{
someview.alpha = 0
} completion::^(BOOL finished)
{
focusAndExposureBox.hidden = true;
}];
I have a case where I am using gesture recognizers and animating a view at the end of a gesture. I have a completion handler which sets someview to hidden (for performance reasons I need to do this). Often interaction is blocked due to the hidden property being set. My previous solution is to use the previous style of animation with an animationDidStop handler
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:.25];
someview.alpha = 0;
[UIView commitAnimations];
However, I'd like to use the newer style if possible, because it has a cleaner method of performing actions after the animation finishes, and is recommended by Apple. So, currently I am using this hackery:
[UIView animateWithDuration:1 delay:0
options:UIViewAnimationOptionAllowUserInteraction animations:^{
someview.alpha = 0;
} completion:^(BOOL finished) {
[someview performSelector:#selector(setHidden:) withObject:[NSNumber numberWithBool:true] afterDelay:1];
}];
Does anyone know of a way to prevent blocking in this case?
You should be able to avoid the Blocking issue if you're using Gesture Recognizers with delegates, as the delegate function will be invoked independent of the main thread.