Trying here develop a side menu, but i'm facing a problem that i cannot figure out why is happening.
Here is a video sample to show what the problem is:
https://www.dropbox.com/s/i97iigus8gj2sl4/problem_side_menu.mov
When I press the menu button the labels appear first than the view controller, what I want is that the latest follow the transition animation.
I have a container view controller that manages all my views controllers.
Already did some research, but I really don't know which keywords use to find useful information.
I really appreciate any help you can provide.
The animation suggests that you have drawn your buttons on wrong view. Make sure your side menu is owner of your button.
What I would recommend doing is fading the UILabels/UIButtons as the transition happens. So in your code that hides the side menu container, do the animations there.
[UIView animateWithDuration:0.2
delay:0.0
options:UIViewAnimationOptionCurveLinear
animations:^
{
self.label.alpha = 0.0;
self.button.alpha = 0.0;
}
completion:^(BOOL finished)
{
if (finished)
{
self.label.alpha = 1.0;
self.button.alpha = 1.0;
}
}];
Related
I am building a page browser that animates pages as 'sheets of paper' being pulled on top of off a stack of papers. In order to keep smooth animations I use 3 UIViews which are stacked on top of each other. These three views hold the current page (on top), the previous page (in the middle) and the next page (at the bottom).
In the code below, I want to drag the top view off to the right, revealing the previous page underneath. This works fine. However, after that I need to move the top page to the bottom of the stack, in order to prepare the stack of three views for the next time the user does a page flip. I use the sendSubviewToBack method for this.
My problem is that ViewSample[Top] is sent to the bottom of the stack as soon as the animation starts. How can I enforce the animation to finish (so that ViewSample[Top] has moved out of the screen completely) before it is sent to the bottom of the stack?
ViewSample[Top].center = CGPointMake(x,y);
[UIView animateWithDuration:0.5
animations:^
{
ViewSample[Top].center = CGPointMake(x+w,y); //slide away to the right
}
completion:^(BOOL finished)
{
}
];
[self.MainView sendSubviewToBack:ViewSample[Top]];
EDIT
i just ran into a very peculiar behaviour which has to do with my problem.
I followed your advice, and found that the behaviour in the 'finished' section of the animation depends on the value of the variable 'top' when it is set AFTERWARDS:
ViewSample[Top].center = CGPointMake(x,y);
[UIView animateWithDuration:0.5
animations:^
{
ViewSample[Top].center = CGPointMake(x+w,y); //slide away to the right
}
completion:^(BOOL finished)
{ [self.MainView sendSubviewToBack:ViewSample[Top]];
}
];
Top++; // THIS COMMAND AFFECTS THE LINE ABOVE!!!
In other words, when I add the line 'Top++;' another View is moved back on the stack, even though the statement sendSubviewToBack came first. This is very confusing to me. Does this make sense? Is it a bug?
The other answers correctly identified the issue. What you're running into with your updated code is a problem of execution order:
Because completion is executed only after the animation completes, your code actually executes in this order:
ViewSample[Top].center = CGPointMake(x,y);
ViewSample[Top].center = CGPointMake(x+w,y);
Top++;
[self.MainView sendSubviewToBack:ViewSample[Top]];
There are two possible solutions. You can either store the view in a variable so you have the same view in all your calls, or you can delay setting the value of Top until completion.
Option 1
UIView *viewMovingFromTopToBottom = ViewSample[Top];
viewMovingFromTopToBottom.center = CGPointMake(x,y);
[UIView animateWithDuration:0.5 animations:^{
viewMovingFromTopToBottom.center = CGPointMake(x+w,y); //slide away to the right
} completion:^(BOOL finished) {
[self.MainView sendSubviewToBack:viewMovingFromTopToBottom];
}];
Top++;
// Other code that depends on the new value of Top...
Option 2
ViewSample[Top].center = CGPointMake(x,y);
[UIView animateWithDuration:0.5 animations:^{
ViewSample[Top].center = CGPointMake(x+w,y); //slide away to the right
} completion:^(BOOL finished) {
[self.MainView sendSubviewToBack:ViewSample[Top]];
Top++;
// Other code that depends on the new value of Top...
}];
Which option makes the most sense to you depends on what you're doing. If you're chaining animations together, you may want to move most of your code into the completion block to delay it until the slide animation completes. If you have a lot of work that needs to be done right away without dependencies on animation, you may want to use option 1 to configure you animations and move on. Or you may want a mix.
Use the completion block:
ViewSample[Top].center = CGPointMake(x,y);
[UIView animateWithDuration:0.5
animations:^
{
ViewSample[Top].center = CGPointMake(x+w,y); //slide away to the right
}
completion:^(BOOL finished)
{
[self.MainView sendSubviewToBack:ViewSample[Top]];
}
];
Brian Nickel's first suggestion (local variable) did the trick. However, there was a caveat: you have to be careful in the order of statements. This does not work:
[self.MainView addSubview:LocalView];
LocalView = View[1];
...whereas this does:
LocalView = View[1];
[self.MainView addSubview:LocalView];
I first had the top version, which just makes the blank view appear.
So a working approach is to use three global views to do the page caching, and use two local views for the animation. The local views are stacked in the appropriate order, copy the data from the global views and then perform the animation.
I would prefer first download the project from below link and then continue with question (only 36kb)
Download Link
At start what I have is like below.
When I click My Office button, I am calling action actionSeenButton which will print NSLog(#"actionSeenButton");
- (IBAction)actionSeenButton:(id)sender {
NSLog(#"actionSeenButton");
}
This works perfect.
When I click, Show hidden button, I am sliding view by 100 and showing the image and buttons that I have at the top, as shown in below image
Code used is
- (IBAction)showHiddenButton:(id)sender {
CGAffineTransform translation = CGAffineTransformIdentity;
translation = CGAffineTransformMakeTranslation(0, 100);
[UIView beginAnimations:nil context:nil];
self.view.transform = translation;
[UIView commitAnimations];
}
When I click this button, I am calling action actionHiddenButton which will print NSLog(#"actionHiddenButton");
- (IBAction)actionHiddenButton:(id)sender {
NSLog(#"actionHiddenButton");
}
BUT the problem is, when I click the new button that I see, action is not getting called.
Any idea why this is happening?
Note
When I move the top hidden button from y=-70 to y=170, action is getting called.
Sample project can be downloaded from here
What I wanted to implement is, showing three buttons (as menu) on the top in one line by moving view down.
verify that your button is not behind the frame of another view. even if the button is visable, if there is something covering it up it wont work. i don't have access to xcode at the moment but my guess is your view "stack" is prohibiting you from interacting with the button. a button is esentually a uiview and you can do all the same animations to buttons and labels that you can with views. your best bet is to leave the view in the background alone and just move your buttons. since your "hidden" button isn't part of your main "view" hiarchy thats where your problem is.
upon further investigation, your problem is related to auto-layout and making sure your button object stays in the view hierarchy. if you turn off auto-layout you will see where the problem is. when you animate the main view down the "hidden" button is off of the view and there for inactive. the easiest solution is to just animate the buttons. the next best solution closest to what you have is to add another view onto your "main view" and then put the buttons into that view. also why do you have that background image twice? why not just set the background color of your view to that same yellow?
I downloaded your project and it seems the translation you're making for self.view. So the actionHiddenButton is not in the frame.Its better to have the controls you want to animate in the separate view.
If you want to see the problem, after your view get transformed set clipsToBounds to YES. Like
self.view.transform = translation;
self.view.clipsToBounds = YES;
Yipeee!!! Below is how I did.
.h
Added new variable.
#property (retain, nonatomic) NSString *hideStatus;
.m
-(void) viewDidAppear:(BOOL)animated {
NSLog(#"viewDidAppear");
CGAffineTransform translation = CGAffineTransformIdentity;
translation = CGAffineTransformMakeTranslation(0, -100);
self.view.transform = translation;
self.view.clipsToBounds = YES;
[UIView commitAnimations];
self.view.frame = CGRectMake(0,-80,320,560);
hideStatus = #"hidden";
}
- (IBAction)showHiddenButton:(id)sender {
NSLog(#"hideStatus===%#", hideStatus);
CGAffineTransform translation = CGAffineTransformIdentity;
if ([hideStatus isEqualToString:#"hidden"]) {
translation = CGAffineTransformMakeTranslation(0, 0);
hideStatus = #"shown";
} else {
translation = CGAffineTransformMakeTranslation(0, -100);
hideStatus = #"hidden";
}
[UIView beginAnimations:nil context:nil];
self.view.transform = translation;
self.view.clipsToBounds = YES;
[UIView commitAnimations];
}
Attached is the sample project. You can download from here.
I created some animations in my project. Basically, I use UIView animate and CGAffineTransform, but a very strange thing happened and I have no idea. Hope someone can help me solve this problem. Thanks in advance.
This is the strange thing:
After the user clicks on a button, the button slides off screen and another two buttons slide on the screen (I just changed the center point of these buttons to achieve this animation). And, some time later, a view on the screen start shaking (I use CGAffineTransform to achieve this).
At this moment, the strange thing happens - the button that previous slid off screen show up at its original position again and the other two buttons disappear (No animation, just shows up and disappear).
The following is the related code,
1) Button slide off and slide in animation related code
- (IBAction)start:(id)sender
{
// 1. Slide in cancel and pause button
[UIView animateWithDuration:0.5f animations:^{
[startButton setCenter:CGPointMake(startButton.center.x + 300.0f, startButton.center.y)];
[cancelButton setCenter:CGPointMake(cancelButton.center.x + 300.0f, cancelButton.center.y)];
[pauseButton setCenter:CGPointMake(pauseButton.center.x + 300.0f, pauseButton.center.y)];
} completion:^(BOOL finished) {
if (finished) {
NSLog(#"Move finished");
}
}];
}
2) The view shaking animation related code
- (void)shakeView:(UIView *)viewToShake
{
CGFloat t = 2.0;
CGAffineTransform translateRight = CGAffineTransformTranslate(CGAffineTransformIdentity, t, 0.0);
CGAffineTransform translateLeft = CGAffineTransformTranslate(CGAffineTransformIdentity, -t, 0.0);
viewToShake.transform = translateLeft;
[UIView animateWithDuration:0.07 delay:0.0 options:UIViewAnimationOptionAutoreverse|UIViewAnimationOptionRepeat animations:^{
[UIView setAnimationRepeatCount:2.0];
viewToShake.transform = translateRight;
} completion:^(BOOL finished) {
if (finished) {
[UIView animateWithDuration:0.05 delay:0.0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
viewToShake.transform = CGAffineTransformIdentity;
} completion:nil];
}
}];
}
This isn't weird, it's a common problem with
auto layout. If you move UI elements by changing frames, then as soon as something else takes place that requires laying out views, the moved views will revert to the position defined by their constraints. To fix it, you either need to turn off auto layout, or do your animations by changing constraints not frames.
I have tried your code in my test project. The problem is probably because you are using Autolayout in your xib.
Please checking your xib file and uncheck the Autolayout property.
I have to give a delete thumbnail animation in my ipad application just like iphone/ipad applications delete effect.
Any body help me please sample photo is attached
If you need more details then kindly mention it in comments
I have done this using CGAffineTransformMakeRotation. Don't know there is some other better method. But What I have done is my logic you can copy that as it is and you just need to add a delete button on the left top of that view. In the following code I am just animating the thumbnail or any view just like iPad does on its home screen. One thing, You need to declare int direction globally. and every time when you will call this method you will set direction = 1;
-(void)shakeToDelete:(UIView *)shakeMe
{
[UIView animateWithDuration:0.1 animations:^
{
shakeMe.transform = CGAffineTransformMakeRotation(0.05 * direction);
}
completion:^(BOOL finished)
{
direction = direction * -1;
[self shakeToDelete:shakeMe];
}];
}
/// edit
I tried this way and got it working in my sample screen as attached in photo
You better should use an autoreverse and looped animation, cause creating animations over and over will fulfill the phone memory.
With this code, only one animation is retained.
view.transform = CGAffineTransformMakeRotation(-kDeleteAnimationAmplitude);
[UIView animateWithDuration:0.1 delay:0 options:UIViewAnimationOptionRepeat|UIViewAnimationOptionAutoreverse animations:^{
view.transform = CGAffineTransformMakeRotation(kDeleteAnimationAmplitude);
} completion:nil];
Then if you want to stop your animation, just call:
[view.layer removeAllAnimations];
[UIView transitionWithView:imageView
duration:3.0
options:UIViewAnimationOptionTransitionCrossDissolve
animations:^{
imageView.image = [UIImage imageNamed:[welcomePhoto objectAtIndex:photoCount]];
}
completion:^(BOOL finish){
}];
When the animation transition at the three second,
imageView can't receive custom gesture,
other times is fine.
How can i fix it? Thanks.
The reason : when UIView animation starts from one point to another, the actual view goes to the new position straight away but it is just hidden. And the view you see moving is just an illusion.
My Given reason is based on paul hagerty's stanford lecture about animation.
The solution to this can be found in other given answer.