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.
Related
Let's say I have a class that is a subclass of UIViewController named FullSizeViewController. I also have another class that is a subclass of UIViewController called TQHViewController (TQH: Three Quarter Height). How would I
be able to display TQHViewController over FullSizeViewController, with the only one quarter of FullSizeViewController visible?
animate this action?
I'm basically attempting to make something like a UIPopover, but animate it so it slides in from the bottom of the screen.
#property(nonatomic,retain) TQHViewController *template;
template = [[TQHViewController alloc]init];
template.view.frame = CGRectMake(20, 1000, 280, 450);
And you can also set the frame for the subView and decide the size of the subview. if you want animation from the bottom use UIViewwithanimation.
[UIView animateWithDuration:0.9f
delay:0.1f
usingSpringWithDamping:0.65f
initialSpringVelocity:0.1f
options:UIViewAnimationOptionCurveEaseOut animations:^{
template.view.frame = CGRectMake(20, 63, 280, 450);
[self.view addSubview:overlayWindow];
}
completion:^(BOOL finished) {
//Completion Block
}];
Use like this so your functionalities will not be lost and make nill after the usage.
If anything wrong feel free to comment it.
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.
Does anyone know how to achieve the present view controller's view to shrink and put another one over it with a transparency? It is achieved in Tweetbot 3 when you tap on your avatar in the top left on the navigation bar. Should I take a snapshot for example?
In order to achieve this effect you will have to rebuild your view stack from scratch.
So as there is no possibility to change the viewController.view's frame, you'll have to add a kind of container subview a little like this:
#implementation ViewController
#synthesize container;
- (void)viewDidLoad {
[super viewDidLoad];
container = [[UIView alloc] initWithFrame:self.view.frame];
[self.view addSubview:container];
// add all views later to this insted of self.view
// continue viewDidLoad setup
}
Now if you have that, you can animate the shrinking behavior like so:
[UIView animateWithDuration:.5 animations:^{
container.frame = CGRectMake(10, 17, self.view.frame.size.width-20, self.view.frame.size.height-34);
}];
Okay, I assume you are developing for iOS 7, so we'll make use of some new APIs here (for earlier versions there are alternative frameworks). Now since WWDC UIView's got a resizableSnapshotViewFromRect:(CGRect) afterScreenUpdates:(BOOL) withCapInsets:(UIEdgeInsets) method returning a single UIView object.
[UIView animateWithDuration:.5 animations:^{
container.frame = CGRectMake(10, 17, self.view.frame.size.width-20, self.view.frame.size.height-34);
} completion:^(BOOL finished) {
UIView *viewToBlur = [self.view resizableSnapshotViewFromRect:container.frame afterScreenUpdates:YES withCapInsets:UIEdgeInsetsZero];
}];
If you do not want to rewrite your view management, you can also first take a snapshot of your main view this way, set it to the container and then animate only the image. But remember, you can not interact with the captured view then.
When you've got that, you can download the two category files from this repo (They're from WWDC, so directly from Apple!). Basically, what they do is, they add some cool new methods to the UIView class, of which we'll use applyDarkEffect. I haven't tested this, maybe another method fits your needs better here.
Anyways if we implement that into the block and maybe also add a UIImageView to display the blurred overlay, it should look something like this:
[UIView animateWithDuration:.5 animations:^{
container.frame = CGRectMake(10, 17, self.view.frame.size.width-20, self.view.frame.size.height-34);
} completion:^(BOOL finished) {
UIView *viewToBlur = [self.view resizableSnapshotViewFromRect:container.frame afterScreenUpdates:YES withCapInsets:UIEdgeInsetsZero];
UIImage *image = [viewToBlur applyDarkEffect];
UIImageView *blurredView = [[UIImageView alloc] initWithFrame:self.view.frame];
[self.view addSubview:blurredView];
// optionally also animate this, to achieve an even smoother effect
[blurredView setImage:image];
}];
You can then add your SecondViewController's view on top of the stack, so that it's delegate methods will still be called. The bounce effect of the incoming account view can be achieved via the new UIView animation method animateWithDuration:(NSTimeInterval) delay:(NSTimeInterval) usingSpringWithDamping:(CGFloat) initialSpringVelocity:(CGFloat) options:(UIViewAnimationOptions) animations:^(void)animations completion:^(BOOL finished)completion (more on that in the documentation)
I hope that will help you with your project.
I have a simple UIView animation block. In the block, I only change the view's alpha, but the view's frame is also being animated! WTF?
Here's my code:
UIButton *button = [flowerViews objectAtIndex:index];
UIImageView *newGlowView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"grid_glow.png"]];
newGlowView.frame = CGRectMake(0, 0, 130, 130);
newGlowView.center = button.center;
newGlowView.alpha = 0.0;
[scrollView_ addSubview:newGlowView];
[scrollView_ sendSubviewToBack:newGlowView];
[UIView animateWithDuration:0.3 animations:^{
newGlowView.alpha = 1.0;
}];
As you see, I'm creating a new view and adding it to scrollView_. I'm setting the view's position and alpha before adding it to scrollView_. Once it's added, I have an animation block to animate the view's alpha from 0 to 1.
The problem is, the view's position is also being animated! As it fades in, it looks as if it's animating from an original frame of CGRectZero to the one I've assigned it.
Ostensibly, only properties set within the animation block should be animated, right? Is this a bug? Am I missing something?
Thanks!
Perhaps the whole thing being called from an animation block or maybe within an event that is within an animation block like the autorotate view controller delegate methods.
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];