Today, I am trying to get a view to return to its default origin after a cancel. I am using two VCs to do this. One is a footer controller in a tableview, and the other is a modal view, which is presented after the first animation. Whenever I try to go back from the modal view, the origin is still the same one after I did the first animation. Here is the code I am using:
Footer:
-(IBAction)addPerson:(id)sender{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.25];
NSLog(#"%f", self.view.frame.origin.y);
self.view.frame = CGRectMake(0,-368,320,400);
[UIView commitAnimations];
self.tdModal2 = [[TDSemiModalViewController2 alloc]init];
// [self.view addSubview:test.view];
[self presentSemiModalViewController2:self.tdModal2];
}
-(void)moveBack{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.25];
NSLog(#"%f", self.view.frame.origin.y);
self.view.frame = CGRectMake(0,368,320,400);
[UIView commitAnimations];
}
And in the modal view:
-(IBAction)cancel:(id)sender{
[self dismissSemiModalViewController:self];
FooterViewController *foot = [[FooterViewController alloc]init];
self.footer = foot;
// self.footer.view.frame = CGRectMake(0,35,320,400);
[self.footer moveBack];
}
I give the following recommendations, they may be good for you.
Note 1, AffineTransform
If the translation is always to the same point and always with the same measure, I'd recommend using CGAffineTransformMakeTranslation(<#CGFloat tx#>, <#CGFloat ty#>) instead of modifying the view's frame. This method specifies how much x and y points will the view move.
In that way, returning the view to the original position is as simple as doing view.transform = CGAffineTransformIdentity.
Both of these inside their respective animation block of course.
Note 2, Using CGPoint to move the origin
If you just move the origin of the view then the recommendation is to make:
CGRect hiddenFrame = self.view.frame;
hiddenFrame.origin.y -= 736;
self.view.frame = hiddenFrame;
or
CGRect hiddenFrame = self.view.frame;
hiddenFrame.origin.y = -368;
self.view.frame = hiddenFrame;
or
CGRect hiddenFrame = self.view.frame;
hiddenFrame.origin = CGPointMake(0,-368);
self.view.frame = hiddenFrame;
The same for the move back. It's more code but it's more understandable.
Note 3, UIView animation block
You should use the new blocks:
[UIView animateWithDuration: 0.25 animations: ^(void) {
//animation block
}];
There are other blocks with more methods as delay, completion blocks, etc.
Option, Delegate or reference passing
When you create your modal controller, pass the reference of the current controller:
self.tdModal2 = [[TDSemiModalViewController2 alloc]init];
self.tdModal2.delegate = self;
You should declare that property in the TDSemiModalViewController2.h. Either by declaring the #class FooterViewController to avoid crossed imports; by making a protocol and declaring the property as id<myModalProtocol>, FooterViewController should then implement the protocol with the method moveBack; Or just declare the property as id and call [self.delegate performSelector: #selector(moveBack)].
Then in the cancel method, simply do:
[self dismissSemiModalViewController:self];
[self.delegate moveBack] //or performSelector.. in the third option case
Related
i am new to IOS programming. i have a background image on my screen. What i want is when app launches screen shows with the background image and then after 1 sec 2 buttons comes up from right side of the screen. how can i do this. here is the image what i am trying to do
button 1 and button2 have to be invisible first. after 1 second they comes up from right side.
if there are any tutorials related to this kind of animation then please share
You can use simple UIView Animations to achieve this.
Set your button x origin any value greater than screen size so that it is not visible first. Then reset the button frame to a visible value with view animation. For example call the following function in your viewWillAppear: method.
- (void) animateButton {
// Setting button origin to value greater than the view width.
CGRect frame = button.frame;
frame.origin.x = self.view.frame.size.width+10;// or set any value > 320
button.frame = frame;
[UIView animateWithDuration:0.5
delay:2.0
options: UIViewAnimationCurveEaseOut
animations:^{
button.frame = CGRectMake(20, 100, 60, 25) ;// Any value according to your requirement
}
completion:^(BOOL finished){
NSLog(#"Done!");
}];
}
Refer Tutorial
You can do it this way, please note that, if you want to animate the way your button shows up, you must hide them using alpha = 0.0f (and not hidden = true). This way, you will have a smooth showing up animation !
Here it is :
First, on your viewDidLoad of your UIViewController, you have to set up a NSTimer of 1sec, then let it call the method that will let your buttons appear :
- (void) viewDidLoad {
[super viewDidLoad];
// Do your init stuff here
// We will call your buttons as if they are declared as properties of your class, ask if you don't know how to set them
self.button1.alpha = 0.0f;
self.button2.alpha = 0.0f;
// This will wait 1 sec until calling showButtons, where we will do the trick
NSTimeInterval timeInterval = 1.0;
[NSTimer scheduledTimerWithTimeInterval:timeInterval target:self selector:#selector(showButtons) userInfo:nil repeats:NO];
}
- (void) showButtons {
[UIView beginAnimations:#"buttonShowUp" context:nil];
[UIView setAnimationDuration:0.5]; // Set it as you want, it's the length of your animation
self.button1.alpha = 1.0f;
self.button2.alpha = 1.0f;
// If you want to move them from right to left, here is how we gonna do it :
float move = 100.0f; // Set it the way you want it
self.button1.frame = CGRectMake(self.button1.frame.origin.x - move,
self.button1.frame.origin.y,
self.button1.frame.size.width,
self.button1.frame.size.height);
self.button2.frame = CGRectMake(self.button2.frame.origin.x - move,
self.button2.frame.origin.y,
self.button2.frame.size.width,
self.button2.frame.size.height);
// If you want to set them in the exact center of your view, you can replace
// self.button1.frame.origin.x - move
// by the following
// (self.view.center - self.button1.frame.size.width/2)
// This way, your button will be centered horizontally
[UIView commitAnimations];
}
Ask if you have any questions !
Set the buttons' x co-ordinates such that the button is just outside the screen on the right side.
And then try the following in your viewDidLoad()
[UIView animateWithDuration:0.5
delay:1.0
options:NO
animations:^{ change your button x co- ordinate here to the co-ordinate you need it on finally}
completion:NULL];
I have a tabbed application for iPad. On the first tab I have a separate menu with a pointer that highlights the currently active menu button. The pointer (a UIImage) is animated into position after tapping the button.
The problem is when you leave the highlighted image on any button that's not the original/default button and move to another tab in the application, then back again, the image has moved back to the default location. However, when you tap another button the image moves in the wrong direction. I think it's because the image moves back but the old coordinates are retained, or the other way around? It's a bit hit and miss and behaves differently testing in the simulator compared to directly on the iPad.
I think I need to start with absolute coordinates and stick with them throughout the process. But I can't get my head around how to achieve it with the CGAffine functions.
Here is my current code
- (IBAction)diplayForm1:(id)sender {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
buttonHighlightImage.transform = CGAffineTransformMakeTranslation(0, 0);
[UIView commitAnimations];
}
- (IBAction)diplayForm2:(id)sender {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
buttonHighlightImage.transform = CGAffineTransformMakeTranslation(0, 80);
[UIView commitAnimations];
}
- (IBAction)diplayForm3:(id)sender {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
buttonHighlightImage.transform = CGAffineTransformMakeTranslation(0, 160);
[UIView commitAnimations];
}
EDIT - - -
#Mundi I tried the code you suggested. I'm assuming by newFrame you mean define a new UIImageView and property which I did in the .h (I called it 'sfh'), then #synthesize in the .m.
This is my code in the .m
-(void)viewWillAppear:(BOOL)animated {
// The "pointer" and the "old" frame are the same so I thought it pointless to do
// selectedFormHighlight.frame = selectedFormHighlight.frame;
// I tried anyway and also tried this and many other combinations
selectedFormHighlight.frame = sfh.frame;
}
-(void)viewDidAppear:(BOOL)animated {
[UIView beginAnimations:nil context:NULL];
[UIView animateWithDuration:0.3 animations:^{
selectedFormHighlight.frame = CGRectMake(0,0,0,0);
}];
[UIView commitAnimations];
}
When I run this the pointer animates off the screen (top-left) and doesn't come back. I have tried every possible combination I can think of in viewWillAppear and viewDidAppear but it makes no difference. I tried removing the other lines in viewDidAppear and it still does the same thing.
I think you're suggesting to animate the pointer from the original (default) position when the user returns from another screen. I don't want that, it should simply remain in the same spot where they left it without animation. Or at least put it back there without them realizing it. The only animation is when they choose to tap a different button within that view.
The reason you are experiencing this is that the actual view object and its presentation layer get mixed up when the view is hidden and redisplayed. The solution is to change the view properties rather than animate the layers.
Thus, you do not need to use affine transforms. Just set the new position of the pointer view directly by changing its frame or center.
The more up-to-date format to do this is with block based animations:
[UIView animateWithDuration:0.5 animations:^{
pointer.frame = newFrame;
}];
Also, it seems very inefficient to have three methods just differing by one variable. You could just multiply the desired y position by 80.
Edit:
Another reason your button resets is because that is where it was put when the view is instantiated. Just set the position of your view in viewWillAppear of your view controller and then animate it to the new location in viewDidAppear.
I appreciate the help from #Mundi but couldn't get it to work that way. I eventually arrived at the following code.
// This initially sets the frame with a variable value that
// corresponds to the current child view
-(void)viewDidAppear:(BOOL)animated {
selectedFormHighlight.frame = CGRectMake(0, self.getY, 250, 4100);
}
// Button actions (converted to a single action instead of one for each button)
// This was done by referencing a tag added to each button (the button tags
// match the children's tags)
-(IBAction)goToForm:(id)sender {
UIButton *btn = (UIButton *)sender;
self.currentChild = self.formViewControllers[btn.tag];
[UIView beginAnimations.nil context:NULL];
[UIView animateWithDuration:0.3 animations:^{
selectedFormHighlight.frame = CGRectMake(0, self.getY, 250, 4100);
}];
[UIView commitAnimations];
sfh.frame = selectedFormHighlight.frame;
}
// This returns the 'y' (vertical center position) of the pointer
// frame for each of the child views
-(int)getY {
switch(_currentChild.view.tag) {
case 1:
return -2005;
break;
case 2:
return -1925;
break;
default:
return -1845;
break;
}
}
My class inherit from UITableViewCell, i have make some custom transitions to push a new detail view when an image get selected.
[UIView transitionWithView:self.masterView duration:0.5 options:UIViewAnimationOptionShowHideTransitionViews
animations:^ {
[self.masterView addSubview:self.detailImage];
}
completion:nil];
My code works fine, the detailImage subview is shown with a transition, but this transition is not what i want exactly. What i want to perform is a simple transition from bottom to up. The list of UIViewAnimation doesn't contain such animation.
Is there any way to use that transition without changing my class inheritance to UINavigationController ?
If I understand you right, the code below may be what you want.
CGRect detailImageFrameOri = self.detailImage.frame;
CGRect detailImageFrame = detailImageFrameOri;
detailImageFrame.origin.y += self.detailImage.frame.size.height;
self.detailImage.frame = detailImageFrame;
[self.masterView addSubview:self.detailImage];
[UIView animateWithDuration:0.5 animations:^{
self.detailImage.frame = detailImageFrameOri;
}];
Hope this can help you.
Edit:
from top to bottom,
CGRect detailImageFrame = self.detailImage.frame;
detailImageFrame.origin.y += self.detailImage.frame.size.height;
[self.masterView addSubview:self.detailImage];
[UIView animateWithDuration:0.5
animations:^{
self.detailImage.frame = detailImageFrame;
}
completion:^(BOOL finished) {
[self.detailImage removeFromSuperview];
}];
I want to create a View outside of the visible screen and push in it (like the default pushViewController animation), but I cannot create the UIView outside. I was trying this code here, but it doesn't work. The View gets always created and displayed in the current UIScreen bounds. That means instead of both views, the one to get pushed out and the one to get pushed in, only the view that goes out "moves", the new view just sits at it's place.
In the the .m of the view to show:
- (void)viewDidLoad
{
[super viewDidLoad];
// set the views frame off the screen
self.view.frame = CGRectMake(320, 0, 320, 460);
}
In the method that actually does the transition:
-(void)showOverview:(UIViewController *)sender //sender = mapviewController
{
NSLog(#"overview");
// current view (frame) = mapviewCOntroller.view
CGRect outFrame = self.view.frame;
if (!self.overviewViewController) {
self.overviewViewController = [[UCOverviewViewController alloc] init];
self.overviewViewController.transitionDelegate = self;
// create a new View for the overview
[self.overviewViewController.view setCenter:self.view.center];
[self.view.window addSubview:self.overviewViewController.view];
[self.view.window bringSubviewToFront:self.mapViewController.view];
}
CGRect inFrame = self.overviewViewController.view.frame;
outFrame.origin.x = outFrame.origin.x-outFrame.size.width;
inFrame.origin.x = self.view.frame.origin.x;
[UIView animateWithDuration:0.5f animations: ^{
[self.view setFrame:outFrame];
}];
}
EDIT: this is my final code, at least the important part. Now, the view thats currently visible gets slider off screen at the same time the off-screen view gets slide in.
-(void)showOverview
{
if (!self.overviewViewController) {
NSLog(#"OverviewViewController created!");
self.overviewViewController = [[UCOverviewViewController alloc] init];
self.overviewViewController.transitionDelegate = self;
// add the subView
[self.view addSubview:self.overviewViewController.view];
[self.view sendSubviewToBack:self.overviewViewController.view];
}
CGRect outFrame = self.mapViewController.view.frame;
CGRect inFrame = self.overviewViewController.view.frame;
outFrame.origin.x -= outFrame.size.width;
inFrame.origin.x = self.view.frame.origin.x;
self.isOverviewViewVisible = YES;
[UIView animateWithDuration:0.5f animations: ^{
[self.mapViewController.view setFrame:outFrame];
[self.overviewViewController.view setFrame:inFrame];
}];
}
your problem is this line.
self.overviewView = self.overviewViewController.view;
You're overriding the view you created with the view you already have.
the following is not a great way to do it but it should work with what I think you have.
- (void)viewDidLoad {
self.overviewViewController.view.frame = CGRectMake(320, 0, 320, 460);
self.overviewViewController.view.backgroundColor = [UIColor blueColor];
}
Then you want another action to do the animations.
[UIView animateWithDuration:0.5f animations: ^{
self.overviewViewController.view.frame = CGRectMake(0,0,320,460);
}];
There are weird and incorrect things in your code that make it confusing to understand what is actually going on, but... forget about using the window anywhere. The only thing you need to worry about, is this. Say View A is your main view. View B is the view you want outside and to come in over A. Then, create B either from nib or manually, add it as a subview to view A, and before you enter the animation block to move it into place, make sure that the current frame is set to {ViewA.bounds.size.width, 0, ViewB.bounds.size.width, ViewB.bounds.size.height}. Assuming you want it to come in from the top right.
iPad - iOS 5.1 - Xcode 4.3.2
When the keyboard pop ups I animate the y origin of my UIImageView up by "x"
When the keyboard goes down, i animate it back down by the same "x"
So the keyboard pops up, the image goes up by X, the keyboard comes down, the image goes down by x, but it doesn't end up in the same place!. You go up 60, down 60, and you're not in the same place! it's further down, as if the coordinate system changed between the appearance of the keyboard and the disappearance of it. It absolutely drives me crazy. I can't understand why this happens.
//add gesture recognizer when keyboard appears
-(void)keyboardWillShow:(NSNotification *) note {
[self.view addGestureRecognizer:tapRecognizer];
// Setup the animation
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.3f];
[UIView setAnimationCurve:UIViewAnimationOptionCurveEaseInOut];
[UIView setAnimationBeginsFromCurrentState:YES];
// The transform matrix: Logo Image
CGAffineTransform moveLogo = CGAffineTransformMakeTranslation(0, -60);
self.logoImageView.transform = moveLogo;
// Commit the changes
[UIView commitAnimations];
}
//add gesture recognizer when keyboard appears
-(void)keyboardWillHide:(NSNotification *) note {
[self.view removeGestureRecognizer:tapRecognizer];
// Setup the animation
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.3f];
[UIView setAnimationCurve:UIViewAnimationOptionCurveEaseInOut];
[UIView setAnimationBeginsFromCurrentState:YES];
// The transform matrix: Logo Image
CGAffineTransform moveLogo = CGAffineTransformMakeTranslation(0, 60);
self.logoImageView.transform = moveLogo;
// Commit the changes
[UIView commitAnimations];
}
That's because you are not translating it, when you use CGAffineTransformMakeTranslation you are saying Give me these coordinates not give me this offset. In other words, make translation gives you the translation from the identity matrix. The function you want is CGAffineTransformTranslate. This will apply the translation to the current transform (passed as the first argument).
the transform property is not cumulative. You are not doing what you think you're doing. You are calculating the new transform from your identity, not from the current transform.
Instead of:
CGAffineTransform moveLogo = CGAffineTransformMakeTranslation(0, 60);
self.logoImageView.transform = moveLogo;
Try:
self.logoImageView.transform = CGAffineTransformIdentity;
Instead of messing around with Core Graphics you might want to animate simple view properties, like frame or size. For example:
[self.logoImageView.center = CGPointMake(self.logoImageView.center.x,
self.logoImageView.center.y + 60);
Do this between beginAnimations and commitAnimations