Hi there I'm having some problems coding an animation for a UIView in my iPhone app. I'm trying to set an animation for the frame of the UIView after i updated the frame property. Here is the code.
//old frame values are: 0, 0, 15, 37
//set the frame for hiding the arrow
[arrow setFrame:CGRectMake(-15, 100, 15, 37)];
//Create an animation to let the arrow slide in the view.
[UIView beginAnimations:#"SlideInArrow" context:nil];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationBeginsFromCurrentState:true];
[UIView setAnimationDuration:1.0];
[symbolArrow setFrame:CGRectMake(0, 100, 18, 37)];
[UIView commitAnimations];
this code is a part of a method i wrote. It will be fired when the user is pressing a button. i suggest, that the UI won't update the new frame values to the object. Instead the animation uses the old values. Why is it so? Is there a way to get the view or the animation to get the new frame values?
You're setting animationBeginsFromCurrentState:, which explicitly tells the system to animate based on where the view currently is on the screen. At this point in time, the frame is still at {0,0} because the run loop hasn't completed, so none of your previous setFrame: transactions have been applied. First, take this line out, which may fix it by itself. If not, there are other ways to set the fromValue the way you describe.
The basic flow is odd, however. If the code is as you suggest, the arrow is on screen at {0,0}, and you're going to make it vanish and slide back on. Is that really the animation you're going for, or is there more animations that you've left out? What's the full effect you're trying to achieve?
Note that you have arrow in one case and symbolArrow in another, which I assume is a typo, but would definitely be a problem if these were different objects.
replace this line
[symbolArrow setFrame:CGRectMake(0, 100, 18, 37)];
To
[arrow setFrame:CGRectMake(0, 100, 18, 37)];
and also
remove this line
[UIView setAnimationBeginsFromCurrentState:true];
Related
I have a gesture which action moves a UIView to point B from point A. How can I add a nice transition of the UIView moving from point A to point B. I am looking at making it slowly move from point A to point B. How would I do this? At the moment to move the item I set the frame to point B.
check this code and set frame what you want
[UIView animateWithDuration:0.75 animations:^{
button.frame = CGRectMake(10, 70, 100, 100);
}];
If you're using auto-layout (and you almost certainly are - it's the default) then #PinkeshGjr s solution is likely to have problems. With AutoLayout you can't manipulate a view's frame directly. At some point after moving the frame the view's constraints can snatch it back.
Instead, you want to create constraints that control the property/properties that you want to animate (x and y position in this case) and control-drag from the constraints into your view controller's header to create outlets.
Then you want to change the constant value on the constraints and call layoutIfNeeded inside your animation code. Something like this:
buttonXConstraint.constant = 100;
buttonYConstraint.constant = 100;
[UIView animateWithDuration:0.75 animations:^{
[self.button layoutIfNeeded];
}];
The code above assumes that you've created 2 constraint outlets and called them buttonXConstraint and buttonYConstraint.
You can achieve that by using animateKeyframesWithDuration or animateWithDuration:animations but it will be just a linear interpolation. If you want to have more control over the animation I recommend that you take a look at MTAnimation it's really a powerful and easy to use Lib for achieving beautiful animations
Cheers
Very nice helper method to use for animating view.
- (void) animateView:(UIView *)view ToFrame:(CGRect) frame withDuration:(float) duration withDelay:(float) startDelay
{
[UIView animateWithDuration:duration delay:startDelay options:0 animations:^{
view.frame = frame;
} completion:^(BOOL finished)
{
// Completion actions
}];
}
Is there something I'm missing here?
i want the imageview to slide in then slide out from the bottom of the screen.
also, this seems to put the UIImageView behind the navigation bar how can I make a CGRect to fit the screen under the navbar?
_finga = [[UIImageView alloc] initWithFrame:CGRectMake(0, 88, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height-88)];
hiddenFrame = CGRectOffset(_finga.frame, 0, _finga.frame.size.height);
_finga.frame = hiddenFrame;
[self.view addSubview:_finga];
_finga.image = [UIImage imageNamed:#"Finga"];
[UIView animateWithDuration:2.0 animations:^{
_finga.frame = self.view.bounds;
}completion:^(BOOL done) {
if (done) {
NSLog(#"Complete!");
[UIView animateWithDuration:2.0 animations:^{
_finga.frame = hiddenFrame;
}];
}
}];
The CGRect you initialize _finga with would put it under the nav bar. In the animation, you are setting the frame to the bounds of the view, which would put it behind the bar, since the y value would be 0.
You could write less code by initializing _finga with this frame from the start:
CGRectMake(0,
self.view.bounds.size.height,
self.view.bounds.size.width,
self.view.bounds.size.height-88);
That will put the view off the screen. Then after you add it as a subview and set its image, animate the view back up to this frame:
CGRectMake(0,
88,
self.view.bounds.size.width,
self.view.bounds.size.height-88);
Which will put the view just below the nav bar. Consider also replacing all the hard coded 88s with a variable or #define so that you can play around with it more easily and in case the nav bar height ever changes.
As for the completion block, try logging that #"Complete!" string before you check if done is YES, or put a breakpoint there and see what the value of done is. Your animation may not be completing for some reason, which would explain why the code in the completion block is not being run.
Generally, though, if you are just using the completion block to run another animation after the first one, you don't need to check the done BOOL at all. It's only crucial when something else in your program depends on the state of the animation. For example, the user may click a button which animates something and then takes the user to a different section of the app. But if the user cancels the animation, you may not want to go to the other section after all, so you can check done.
I have two UIViews (My bad it is a UIView and a UIButton) which I am animating at the same time. I originally had a view and a containerView which would animate just fine and worked like a charm.
Now only one of my UIViews will move/animate in animateWithDuration even though through debugging the frame of the other view says that it is in a position it is not.
CGRect rect = self.toggle.frame;
CGRect tabRect = self.tabButton.frame;
rect.origin.x = rect.origin.x - rect.size.width;
NSLog(#"%f Before",tabRect.origin.x);
tabRect.origin.x = tabRect.origin.x - rect.size.width;
NSLog(#"%f After", tabRect.origin.x);
[UIView animateWithDuration:0.3 animations:^{ // animate the following:
self.toggle.frame = rect; // move to new location
self.tabButton.frame = tabRect;
}];
NSLog(#"%f AfterAnimation", tabButton.frame.origin.x);
The toggle view moves fine, but the tabButton view does not animate or move. The strange thing is that both the "After" and "AfterAnimation" debugging code returns the same value, which suggests the frame has indeed moved. Is there a specific reason that this will not work when toggle is a UIView when it would work as a UIContainerView?
Note that if I remove the line
self.toggle.frame = rect;
tabButton will animate correctly, but if I move toggle, tabButton will not move regardless of whether it is first in the animation block or second.
Edit: I have tried moving them into separate blocks and to change the center point rather than the frame, to no avail. It seems that if the toggle view moves, the tabButton will not move.
Edit 2: The pictorial evidence.{
In the following screenshots tabButton bg is green and toggle bg is red.
Above: Initial position (toggle is off-screen) correct position
Above: The problem in question toggle is correct tabButton is not
Above: When self.toggle.frame = rect is commented out (tabButton correct, toggle not)
}
Edit 3: It's even worse than I feared.{
I have done a few more tests and even if I take the toggle change out of the animation block to make it an instant thing, the tabButton will still not animate. This makes me think the tabButton may just fundamentally dislike the toggle view and/or myself so will not move just to spite me.
}
Edit 4:{
If I change the tabButton animation to tabButton.frame = CGRectMake(10,10,100,100) the View snaps instantly to that location and animates back to its original position in the same time as the animation duration.
}
I better add more bookkeeping/TLDR information in case things aren't clear.
toggle is an instance of ToggleDraw which is a subview of UIView which I created.
tabButton is a UIButton which is part of my IB viewController and a property of the class
Both toggle and tabButton are subviews of self.view
The animations will work individually with no modifications to the logic of the rects but will not work if they are animated at the same time
toggle animation seems to take precedence over tabButton animation regardless of the order
I had a problem with the animation of an UIView created in IB (the animation didn't start from the current position of the view, and ended in the initial position).
All worked fine after sending layoutIfNeeded() to the underlaying view before the animation block:
self.view.layoutIfNeeded()
UIView.animateWithDuration(0.5) { () -> Void in
...
I think it is not a problem about a UIView Animation. Maybe your toggle posiztion is related to your tabButton. For a try, your can set toggle frame to a rect lick (10, 10, 100,100), then check the result.
I've created an example of what you describe and everything seems to work fine. This is what I used:
UIView *toggle = [[UIView alloc] initWithFrame:CGRectMake(320, 64, 100, 100)];
[toggle setBackgroundColor:[UIColor redColor]];
[self.view addSubview:toggle];
UIButton *tabButton = [[UIButton alloc] initWithFrame:CGRectMake(220, 64, 100, 100)];
[tabButton setBackgroundColor:[UIColor greenColor]];
[self.view addSubview:tabButton];
CGRect rect = toggle.frame;
CGRect tabRect = tabButton.frame;
rect.origin.x = rect.origin.x - rect.size.width;
NSLog(#"%f Before",tabRect.origin.x);
tabRect.origin.x = tabRect.origin.x - rect.size.width;
NSLog(#"%f After", tabRect.origin.x);
[UIView animateWithDuration:1 animations:^{ // animate the following:
toggle.frame = rect; // move to new location
tabButton.frame = tabRect;
}];
What I can suggest is to make sure that the code is being ran on mainthread:
dispatch_async(dispatch_get_main_queue(), ^{
[UIView animateWithDuration:0.3 animations:^{
self.toggle.frame = rect; // move to new location
self.tabButton.frame = tabRect;
}];
});
Also take into account that the log you have after the animation code is incorrect as it won't run after the animation, but rather right next to asking for the animation.
If you want code to run after the animation you should use:
[UIView animateWithDuration:0.3 animations:^{
self.toggle.frame = rect; // move to new location
self.tabButton.frame = tabRect;
} completion:^(BOOL finished){
NSLog(#"Finished animating!");
}];
I have found a solution to the problem. If I initialise the UIButton (tabButton) programmatically rather than through the interface builder, both views will animate simultaneously.
This however seems very hacky to me, kind of like putting a bandaid over a missing foot and hoping it will sort itself out.
I could not work out the root cause of the problem but at least I could avoid the symptoms.
If anyone knows why the views would not animate when the button was made in the interface builder post an answer here, I am interested in knowing the reason behind this.
Thanks for your help everyone.
I have two animations running; show search bar and show banner. Both those animations are resizing the same view and if they are running on the same time (Which they are) the latest animation will cancel the resize. Is there anyway to check if UIView is currently animating and then standby for animation?
I'm pretty sure I'm not using CAAnimations, since Cocoa not is detecting such class.
This one is running when an ad was received. Unfortunately, that is the same time as ShowSearch is running.
- (void)adViewDidReceiveAd:(GADBannerView *)bannerView {
if (!hasloaded) {
[UIView beginAnimations:nil context:nil];
[UIView setAnimationCurve: UIViewAnimationCurveEaseInOut];
[UIView setAnimationDuration: 1.0];
[bannerView_ setFrame:CGRectMake(0, self.view.frame.size.height, bannerView_.frame.size.width, bannerView_.frame.size.height)];
// move and grow
[bannerView_ setFrame:CGRectMake(0, self.view.frame.size.height-50, bannerView_.frame.size.width, bannerView_.frame.size.height)];
// set original position
[UIT setFrame:CGRectMake(UIT.frame.origin.x, UIT.frame.origin.y, UIT.frame.size.width, UIT.frame.size.height)];
// move and grow
[UIT setFrame:CGRectMake(UIT.frame.origin.x, UIT.frame.origin.y, UIT.frame.size.width, UIT.frame.size.height-50)];
[UIView commitAnimations];
hasloaded = true;
}
}
You can use the completion block in the UIView method +animateWithDuration:animations:completion: (which is a more modern alternative to beginAnimations/commitAnimations) to chain multiple animations (I'm guessing this is what you want to do?).
If you select your code while entering it and press control + K, you will preserve formatting and make it pretty. Try it. Reading the wall of text made from pasting code into a true-type non-color-formatted environment.
Nick Weaver says:
A UIView has a layer (CALayer). You can send animationKeys to it which will give you an array of keys which identify the animations attached to the layer. I suppose that if there are any entries, the animation(s) are running. If you want to dig even deeper have a look at the CAMediaTiming protocol which CALayer adopts. It does some more information on the current animation.
I'm pretty new to iOS animations, I've been trying to accomplish something that in my head seems very simple but I am not sure what would be the best way to implement such a thing.
Usage
User clicks on a tab located on the right side of the app.
A small window slides from the side (or below doesn't really matter direction right now)
The sliding object is a UIScrollView currently
Here's a small draft so you guys have an idea
http://dl.dropbox.com/u/919254/animations.png
The black is the tab, there are severals below. When clicked, the red one shows up from a particular direction.
My questions are:
How could I accomplish an animation like that?
Any good tutorials out there you guys can refer me to?
Seeing sample code here wouldn't hurt!
In your view did load:
// Hide scrollView off screen (x=320 for iPhone/iPod)
scrollView.frame = CGRectMake(320, 0, scrollView.frame.size.width, scrollView.frame.size.height);
[self.view addSubview: scrollView];
In your method for opening the view:
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:1.0];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
// Assuming 0 is the x-coordinate of where you want your view to go
scrollView.frame = CGRectMake(0, 0, scrollView.frame.size.width, scrollView.frame.size.height);
[UIView commitAnimations];
This will animate your scrollView from the right to the left