Is there any way to specify a duration for the animation of [UIScrollView zoomToRect:zoomRect animated:YES]?
At the moment it's either fast animated:YES or instant animated:NO.
I'd like to specify a duration, eg [UIScrollView setAnimationDuration:2]; or something similar.
Thanks in advance!
Use the UIView's animations.
It's a bit long to explain, so I hope this little example will clear things up a bit.
Look at the documantation for further instructions
[UIView beginAnimations: nil context: NULL];
[UIView setAnimationDuration: 2];
[UIView setAnimationDelegate: self];
[UIView setAnimationDidStopSelector: #selector(revertToOriginalDidStop:finished:context:)];
expandedView.frame = prevFrame;
[UIView commitAnimations];
It's from a project I'm currently working on so it's a bit specific, but I hope you can see the basics.
I've had luck with this method in a UIScrollView subclass:
- (void)zoomToRect:(CGRect)rect duration:(NSTimeInterval)duration
{
[self setZoomLimitsForSize:rect.size];
if (duration > 0.0f) {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:duration];
}
[self zoomToRect:rect animated:NO];
if (duration > 0.0f)
[UIView commitAnimations];
[self zoomToRect:rect animated:(duration > 0.0f)];
}
It's kinda cheating, but it seems to mostly work. Occasionally it does fail, but I don't know why. In this case it just reverts to the default animation speed.
Actually these answers are really close to what I ended up using but I'll post mine separately since it is different. Basically the zoomToRect does not work correctly if the destination zoomScale is the same as the current one.
You could try to scrollToRect but I did not have any luck with that.
Instead just use the contentOffset and set it to the zoomRect.origin and nest that in the animation block.
[UIView animateWithDuration:duration
delay:0.f
options:UIViewAnimationOptionCurveEaseInOut
animations:^{
if (sameZoomScale) {
CGFloat offsetX = zoomRect.origin.x * fitScale;
CGFloat offsetY = zoomRect.origin.y * fitScale;
[self.imageScrollView setContentOffset:CGPointMake(offsetX, offsetY)];
}
else {
[self.imageScrollView zoomToRect:zoomRect
animated:NO];
}
}
completion:nil];
Related
I have an animation in my app that grows a UIImageView and then shrinks it (really two animations). Throughout the app this may happen on several different UIImageViews. I found a way to do this that worked really well, but it now doesn't seem to be compatible with Automatic Reference Counting. Here is my code:
[UIView beginAnimations:#"growImage" context:imageName];
[UIView setAnimationDuration:0.5f];
[UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
[UIView setAnimationDelegate:self];
imageName.transform = CGAffineTransformMakeScale(1.2, 1.2);
[UIView commitAnimations];
and then:
- (void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(UIImageView *)context {
if (animationID == #"growImage") {
[UIView beginAnimations:#"shrinkImage" context:context];
[UIView setAnimationDuration:0.5f];
[UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
[UIView setAnimationDelegate:self];
context.transform = CGAffineTransformMakeScale(0.01, 0.01);
[UIView commitAnimations];
}
}
This worked perfectly and I was very happy with it, until I tried converting my project to ARC. I now get the error "Implicit conversion of an Objective-C pointer to 'void *' is disallowed with ARC" on these lines in which I try to pass a UIImageView as the context for the animation:
[UIView beginAnimations:#"growImage" context:imageName];
[UIView beginAnimations:#"shrinkImage" context:context];
Does anybody know of another way that I can alert the "animationDidStop" function of which UIImageView I want it to act on that would be compliant with ARC?
Thanks so much in advance!
Any reason you are not using the much simpler block based animation?
[UIView animateWithDuration:0.5 animation:^{
imageName.transform = CGAffineTransformMakeScale(1.2, 1.2);
} completion ^(BOOL finished) {
[UIView animateWithDuration:0.5 animation:^{
imageName.transform = CGAffineTransformMakeScale(0.01, 0.01);
}];
}];
You can do as follows:
[UIView beginAnimations:#"growImage"
context:(__bridge void*)imageName];
imageName.transform = ...
[UIView commitAnimations];
I have a client who recently requested this:
My thoughts were that the text could be better displayed on the back of a flipover view and that it looks like it could be an issue in the approval process. Is There any way to even do this, do I even want to try? Are there resources you can share?
Thanks in advance.
EDIT: I should clarify that the NavigationBar and the Table would slide over when taping the picture behind. One tap would make it show and the other tap would make the bar and the table hide.
This is actually pretty good. It's often hard to get clients to give you requirements, and this at least shows you what they're trying to achieve. I'd spend some time reworking the UI so that it will be acceptable in the app store (assuming you're going to publish there) and perhaps more in keeping with the normal use of iOS UI elements. Prepare to give your client a bit of an explanation about why this particular design leaves something to be desired, but try to come up with a design that they'll agree is obviously better. (There's plenty of room for improvement here, so it shouldn't be too hard.)
If your client is absolutely wedded to this exact UI, it might be time to find a new client. But if they're reasonable, thoughtful, and a little bit flexible, this might be the beginning of a nice app.
You can do this. Put the picture (UIImageView) inside a wrapper UIView. Put the text in a UITextView also in the wrapper UIView. Then animate a flip transition between them that brings whichever one you want to the bottom of the subview stack.
You can check for potential UI violations in Apple's HIG: http://developer.apple.com/library/ios/#documentation/UserExperience/Conceptual/MobileHIG/Introduction/Introduction.html
+(id)showAlert{
UIViewController *controller = [[UIViewController alloc] initWithNibName:#"Overlay" bundle:nil];
Overlay *alert = (Overlay*)controller.view;
//alert.iTag = iiTag;
alert.tag = iiTag;
return alert;
}
-(void)addAnimation{
self.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.001, 0.001);
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.3/1.5];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(bounce1AnimationStopped)];
self.transform = CGAffineTransformScale(CGAffineTransformIdentity, 1.1, 1.1);
[UIView commitAnimations];
}
- (void)bounce1AnimationStopped {
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.3/2];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(bounce2AnimationStopped)];
self.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.9,0.9);
[UIView commitAnimations];
}
- (void)bounce2AnimationStopped {
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.3/2];
self.transform = CGAffineTransformIdentity;
[UIView commitAnimations];
}
- (CGAffineTransform)transformForOrientation {
UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
if (orientation == UIInterfaceOrientationLandscapeLeft) {
return CGAffineTransformMakeRotation(M_PI*1.5);
} else if (orientation == UIInterfaceOrientationLandscapeRight) {
return CGAffineTransformMakeRotation(M_PI/2);
} else if (orientation == UIInterfaceOrientationPortraitUpsideDown) {
return CGAffineTransformMakeRotation(-M_PI);
} else {
return CGAffineTransformIdentity;
}
}
-(void)stopAnimatton{
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:1.0];
[UIView setAnimationDelay:2.0];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationDelegate:self];
self.transform = CGAffineTransformMake(00.1, 00.1,0.001, 0.001, 0.001, 0.001);
[UIView commitAnimations];
}
I'm using UIScrollView and using scrollRectToVisible:animated
This is working fine for me.
But I want to scroll to a location slowly so that user can notice the effect.
Is it possible.
I'm trying the following code, but didn't succeed.
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:2.0];
[scrlView scrollRectToVisible:<<some cgrect>> animated:YES];
[UIView commitAnimations];
The solution is actually pretty easy. If you use [scrollView scrollRectToVisible:frame animated:YES] the scrollview will start it's own animation, so in order to animate with your duration you have to use [scrollView scrollRectToVisible:frame animated:NO] within your animation.
In other words: This will work.
[UIView animateWithDuration:3
delay:0
options:UIViewAnimationOptionCurveEaseInOut
animations:^{ [scrollView scrollRectToVisible:frame animated:NO]; }
completion:NULL];
I have a working view animation, that curls up a container view, while the containerview.subviews changes. (before the animation a UITableView will be shown, after it is a custom view, name keypadView)
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:.75];
[UIView setAnimationDelegate:self];
[UIView setAnimationTransition:UIViewAnimationTransitionCurlUp
forView:containerView
cache:YES];
[secondView removeFromSuperview];
[containerView addSubview:keypadView];
[UIView commitAnimations];
Now I want to rewrite this code for the iOS4 block-based api, as I want to use the completion block. I wrote this:
[UIView transitionWithView:containerView
duration:.75
options:UIViewAnimationTransitionCurlUp
animations:^{
NSLog(#"Hey Ho");
[secondView removeFromSuperview];
[containerView addSubview:keypadView];
}
completion:NULL];
The views switch — but not animated.
what is wrong with my code?
Edit
completion: ^(BOOL completed){
NSLog(#"completed %d", completed);
}
doesn't help, as NULL is an accepted value, according to the docs
do:
options:UIViewAnimationOptionTransitionCurlUp
instead of:
options:UIViewAnimationTransitionCurlUp
That is why your code works now :).
The sample in the UIView class reference may be wrong - or maybe there's a bug with adding and removing views in the animations block object, but the only way I've been able to get it to work is as follows:
[secondView removeFromSuperview];
[containerView addSubview:keypadView];
[UIView transitionWithView:containerView
duration:.75
options:UIViewAnimationOptionTransitionCurlUp
animations:^{}
completion:^(BOOL finished) {
NSLog(#"finished %d", finished);
}];
Did you leave [UIView beginAnimations:nil context:nil]; above your new block?
Is the completion block always NULL? Try putting an NSLog statement in there or something. I don't know if NULL blocks would mess it up.
I have a UIScrollView and I'm calling scrollRectToVisible:animated:YES on it.
I would like to set the speed at which it is animated. Can that be done?
I ended up finding a solution. In my case, the scrolling was animated programmatically after launch, to mimic a slot machine (with 3 horizontal UIScrollViews). Was doing this with the scrollRectToVisible:animated: method.
I got to set a custom speed using UIView's beginAnimation:
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDelegate:self];
[UIView setAnimationDuration:(abs(rMid-pMid)*0.3)];
scrollMid.contentOffset = CGPointMake(rMid*320, 0);
[UIView commitAnimations];
AnimationDuration depends on the distance the scroller has to move between each "drawing".
A modern version with blocks:
[UIView animateWithDuration:1.0 animations:^{
[self.scrollView scrollRectToVisible:CGRectMake(...) animated:NO];
} completion:^(BOOL finished) {
...
}];