iPhone - How to animate a button when pressed? - iphone

Is there a way to make a custom animation when clicking on an iPhone button? I would like something like the App Store button - it shows the price, and then when you click on it, it changes color and the text changes to buy now, then when you click it again, it completes the purchase.
The UIViewAnimationTransition only contains a few values which don't provide the full functionality. Is it possible to do something like this but with the animation:
- (IBAction) changeButtonDisplay:(id)sender {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.8];
[UIView setAnimationTransition:UIViewAnimationTransitionCurlDown forView:purchaseButton cache:NO]; //the built in UIViewAnimationTransition values don't provide enough flexibility
[purchaseButton setTitle:#"Buy Now" forState:UIControlStateNormal];
[purchaseButton setBackgroundColor:[UIColor greenColor]];
[purchaseButton addTarget:self action:#selector(purchaseItems:) forControlEvents:UIControlEventTouchUpInside];
[UIView commitAnimations];
}
This code works and will display the proper transition and allow for the second click to do the proper action, but the title and color changes instantly, not in a smooth animation. Is it possible to do such an animation easily, of do I have to create a UIButton subclass and do the animation "manually"? If so, what method would I have to override?

Rather than just changing the title and target, etc of the button, have two separate buttons that do each action and look different. Then when you press the button, call a method that removes the current button from its super view and adds the new button to the view in its place. Wrap that up in some UIView animation block and you should get your animation.
Also, for this to work, you'll need to set the animation transition on the superview of the button. So it might be handy to have a 'container view' as it may be and then add you buttons as subviews of that.
Pseudo code might look something like so:
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.8];
[UIView setAnimationTransition:UIViewAnimationTransitionCurlDown forView:buttonConteinerView cache:NO]; //the built in UIViewAnimationTransition values don't provide enough flexibility
[purchaseButton retain];
[purchaseButton removeFromSuperView];
[buttonContainerView addSubview:secondPurchaseButton];
[UIView commitAnimations];

A Standard UIView will do what you want. UIView's backgroundColor is an animatable property.
I would make own "button" by subclassing UIView OR alternatively subclass a UIButton and add subviews to it. (note: UIButtons were a pain about this in 2.2, not sure in 3.0)
You need a UILabel for each text state:
UILabel *textForStateOne;
UILabel *textForStateTwo;
And you can change the background color of the parent view.
So then you make a method in your new button class:
-(void)toggleState{
myState = !myState;
if(myState){
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.8];
[textForStateOne setAlpha:1.0]
[textForStateTwo setAlpha:0.0]
[self setBackgroundColor:[UIColor greenColor]];
[UIView commitAnimations];
} else{
//do the opposite here
}
}

UIView *btnView4=button;
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.5];
[UIView setAnimationTransition:UIViewAnimationTransitionCurlUp forView:btnView4 cache:YES];
[UIView commitAnimations];``

Related

Add a subview to a view more beautifuly?

I want to be able to fade in a sub view. Is there a way to animate that so that when my subview gets added it fades in and not just is all of a sudden pops up there. I know I could get several instances of my imageview with different alphas and then animate it that way but isn't there an easier way?
Yes, you can animate the view without needing different images. The below code will fade your view in over 0.3 seconds.
[myView setAlpha:0.0];
[myView setHidden:NO];
[UIView animateWithDuration:0.3 animations:^{
[myView setAlpha:1.0];
}];
You need only one instance. UIView.alpha can be animated.
You can set the alpha to 0 before adding the subview, and after your addSubview, you make an animation, like that:
yourView.alpha = 0.0f;
[self.view addSubview:yourView];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5f];
yourView.alpha = 1.0f;
[UIView commitAnimations];

iPhone UILabel not updating on first load

I have a UILabel that does not update on first load but does load correctly on every other subsequent load.
Here is the snippet of code. Again, as I said, on the first load only it will display what's specified in the label in the xib, i.e label, and the second time it will load the string label.text= #"Glass, Paper, Cans, Textiles, Card, Shoes and Books";.
-(IBAction)showDetails:(id)sender{
NSLog(#"Annotation Click");
self.userProfileVC.title=((UIButton*)sender).currentTitle;
if([((UIButton*)sender).currentTitle isEqualToString:#"Asda"])
self.userProfileVC.label.text= #"Glass, Paper, Cans, Textiles, Card, Shoes and Books";
[UIView beginAnimations:#"Curl Page Down" context:nil];
[UIView setAnimationDuration:1];
[UIView setAnimationTransition:UIViewAnimationTransitionCurlDown
forView:self.view cache:YES];
//Adjust the Subview by butting up to status bar
self.userProfileVC.view.frame = CGRectMake(0, 0, 320, 480);
//Add userProfileVC as a subview
[self.view addSubview:userProfileVC.view];
[UIView commitAnimations];
}
I believe that at the time you access self.userProfileVC.label at the first time, the label is still nil because the view itself hasn't been loaded yet. The quick fix is that you must load the view first by putting self.userProfileVC.view; statement at the beginning of the showDetails method.
Presumably this code is called when you click your UIButton. So at first UI load I wouldn't expect your method to get called (as no button was pressed). Why don't you try setting up the default text in viewDidLoad or similar?
e.g. something along the lines of:
- (void)viewDidLoad {
self.userProfileVC.label.text= #"Glass, Paper, Cans, Textiles, Card, Shoes and Books";
}
I am such an idiot I have changed the order of my code....load the view first before the labels. DOH!
Heres the snippet:
-(IBAction)showDetails:(id)sender{
//Must load the view before the annotations update the label with the correct label text!
[UIView beginAnimations:#"Curl Page Down" context:nil];
[UIView setAnimationDuration:1];
[UIView setAnimationTransition:UIViewAnimationTransitionCurlDown
forView:self.view cache:YES];
//Adjust the Subview by butting up to status bar
self.userProfileVC.view.frame = CGRectMake(0, 0, 320, 480);
//Add userProfileVC as a subview
[self.view addSubview:userProfileVC.view];
[UIView commitAnimations];
NSLog(#"Annotation Click");
self.userProfileVC.title=((UIButton*)sender).currentTitle;
if([((UIButton*)sender).currentTitle isEqualToString:#"Asda"])
self.userProfileVC.label.text= #"Glass, Paper, Cans, Textiles, Card, Shoes and Books";

Why new UIImageView can not Animating?

I have some code in my iPhone app like that :
//fromView is a UIImageView.
//self is a UIView.
UIGraphicsBeginImageContext(fromView.bounds.size);
[fromView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *dummyFromImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImageView* dummyImageView = [[UIImageView alloc] initWithImage:dummyFromImage];
[self addSubview:dummyImageView];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.5];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView: dummyImageView cache:YES]; //line:9
[UIView commitAnimations];
The dummyImageView only show but never flip, if you change line9's dummyImageView to fromView, fromView do flip, Please tell me why?
I ask this question to Apple Developer Technical Support, they said,
"The basic problem is that because of the timing of your animation there is no "previous" state for Core Animation to animate from, as the view was just added to the view hierarchy, and so when the transition is attempted, all it can do is display the "final" state.
If you instead perform the flip on the next runloop iteration, then Core Animation will have had time to create an initial state for the view's layer, and thus the flip will occur correctly. You can do this by splitting your flip method in two and using -performSelector:withObject:afterDelay: like so:
"
-(IBAction)flip {
UIImageView* dummyImageView = [[UIImageView alloc] initWithImage:fromView.image];
dummyImageView.frame = fromView.frame;
[window addSubview:dummyImageView];
[self performSelector:#selector(animate:) withObject:dummyImageView afterDelay:0.0];
}
-(void)animate:(UIView*)view {
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.5];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView: view cache:YES];
[UIView commitAnimations];
}
However, since you mention that "fromView" is a UIImageView, I wonder why you are using -renderInContext: – it is more efficient to simply use the same image that "fromView" is using and assign it as the image for your new UIImageView, as this saves both CPU time and memory, especially since I notice in your sample that the image is smaller than the view you are using.
[UIView setAnimationTransition:… forView: dummyImageView cache:YES]; //line:9
The view in the -setAnimationTransition:… method should be assigned to the view that contains the change. In your case, self.
The dummyImageView itself is not changed (exterior changes such as changing superview is irrelevant), so the animation can do nothing.

Fading out an UIButton when touched

I've got a Selected-state and a Normal-state for an UIButton that both are UIImages. When a button is touched, I'd like it to hit the selected-state and then animate back to the normal-state over the period of one second. I've set the following animation when the UIButton* btn is pressed, but it just switches right back to deselected state again. How should I go about achieving this?
[btn setSelected:YES];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:1.0f];
[btn setSelected:NO];
[UIView commitAnimations];
Cheers
Nik
Since selected is not an animatable property, that won't work (as you've found out). My solution would be to have the selected state of the btn be in a separate UIImageView directly below the button in the exact same location. Then in the action for tapping the button:
- (void) tapButton:(UIButton *)btn {
btn.alpha = 0;
[[UIApplication sharedApplication] beginIgnoringInteractionEvents];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:1];
[UIView setAnimationDelegate:[UIApplication sharedApplication]];
[UIView setAnimationDidStopSelector:#selector(endIgnoringInteractionEvents)];
btn.alpha = 1;
[UIView commitAnimations];
}
Note I also added the begin/endIgnoringInteractionEvents calls so the user can't tap on the button while it's fading back to its normal state. If you want to allow that, replace the begin/end calls with [UIView setAnimationBeginsFromCurrentState];

Flip Animation not working

I have a Custom view. This custom view has two UIImageViews - imageview1 and imageview2.
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:2.00];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(transitionDidStop:finished:context:)];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:self cache:YES];
if(frontVisible) {
[imageview1 removeFromSuperview];
[self addSubview: imageview2];
}
else {
[imageview2 removeFromSuperview];
[self addSubview: imageview1];
}
frontVisible = !frontVisible;
[UIView commitAnimations];
The image changes from imageview1 to imageview2 and viceversa but I dont get the flip effect. Instead I see the fading out of one image as the other appears.
Not really sure but I checked the documentation and found this:
Discussion
If you want to change the appearance of a view during a transition—for example, flip from one view to another—then use a container view, an instance of UIView, as follows:
Begin an animation block.
Set the transition on the container view.
Remove the subview from the container view.
Add the new subview to the container view.
Commit the animation block.
So it says you have to create a container view in order to make it work properly.
The reason you're not getting the curl transition to work is because the curl transition does not work in the simulator. It shows up as a fade instead.