Changing title of UIButton using animationWithDuration has no delay or animation - ios

I have a start button with initial text "Start" hooked up to an action in Interface Builder.
However, the animation starts and finishes instantly, instead of taking 3 + 5 seconds. What is wrong with this code?
#interface ViewController()
#property (weak, nonatomic) IBOutlet UIButton *startButton;
#end
#implementation ViewController
- (IBAction)startPressed:(UIButton *)sender
{
[UIView animateWithDuration:3 delay:5
options:UIViewAnimationOptionCurveEaseInOut
animations:^{
[self.startButton setTitle:#"New Title" forState:UIControlStateNormal];
}
completion:nil];
}
#end
Update: Of course, these responses are correct. I used Jack Wu's suggestion, though without hiding the text, setTitle makes the button flash back on the screen.
- (IBAction)startPressed:(UIButton *)sender
{
[UIView animateWithDuration:1.5 delay:5
options:UIViewAnimationOptionCurveEaseInOut
animations:^{ self.startButton.alpha = 0; }
completion:^(BOOL c){ if (c) {
self.startButton.hidden = YES;
[self.startButton setTitle:#"newTitle" forState:UIControlStateNormal];
[UIView animateWithDuration:1.5 delay:0 options:UIViewAnimationOptionCurveEaseInOut
animations:^{
self.startButton.hidden = NO;
self.startButton.alpha = 1;
}
completion:nil];
}}];
}

A button's title is not an animatable property, so you're going to see it return immediately. That's by design. You can find the animatable properties of a UIView in its' documentation. Here's what they are as of today.
#property frame
#property bounds
#property center
#property transform
#property alpha
#property backgroundColor
#property contentStretch
Alternately, you can add two subview labels to your button and cross fade them in your animation.

Title is not an animatable property of UIButton. As others have suggested, you would need to create an animation yourself by doing something like fading out the button, changing the title, and fading it back.
You could also write custom animation code that would take a bitmap snapshot of the button, lay that on top of the current button, change the button title under the bitmap snapshot, then fade out and remove the bitmap. That would give you a cross-fade effect, but it would be a fair amount of work.

Related

How can I animate some subviews of a UIViewController "off" the screen, and other views "on" the screen?

Here's what I'm trying to achieve, I've created 3 pictures which do a better job describing what I want to do better than I ever could.
Here's what I want to do...
I want to keep "App Title" right where it is. I also have a UIImageView now that takes up the entire screen where the dark black is, and I want it to stay fixed like "App Title".
However on the first image when the user clicks "Create Account" I want to animate all those buttons left and off the screen, and then animate on the "Create Account" buttons from the right.
How can I do this.
Keep in mind I'm using storyboards and auto layout constraints. I've created the view in Picture #1. Now I need to figure out how to animate on the "Create Account" views. How can I do this, while keep using storyboards/IB and autolayout, and have it fit for all phones of course?
Just give you an example about how to do it
First I suggest you to use a contain view to contain your textfields and button.Then it become animate two contain view.
Drag the constraints of x position as outlet,in this demo,it is center x.Also drag the two contain view
#property (weak, nonatomic) IBOutlet UIView *yellowView;
#property (weak, nonatomic) IBOutlet UIView *greenView;
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *greenConstraint;
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *yellowConstraint;
Then in viewDidLoad,set the yellowView off the screen and set hidden
to YES
- (void)viewDidLoad {
super viewDidLoad];
self.yellowConstraint.constant = CGRectGetWidth(self.view.frame);
[self.view layoutIfNeeded];
self.yellowView.hidden = YES;
}
When click,animate to show the yellow view
- (IBAction)start:(id)sender {
self.yellowConstraint.constant = 0;
self.yellowView.hidden = NO;
self.greenConstraint.constant = -1 * CGRectGetWidth(self.view.frame);
[UIView animateWithDuration:0.5 animations:^{
[self.view layoutIfNeeded];
} completion:^(BOOL finished) {
self.greenView.hidden = YES;
}];
}

UIImageView fade out

In my main storyboard I have a UIViewController with a hidden UIImageView. I read in a thread that to fade an image out I could use the following code. I was wondering how to tie the UIImageView I created with an IBAction.
-(IBAction)popupImage
{
_imageView.hidden = NO;
_imageView.alpha = 1.0f;
// Then fades it away after 2 seconds (the cross-fade animation will take 0.5s)
[UIView animateWithDuration:0.5 delay:2.0 options:0 animations:^{
// Animate the alpha value of your imageView from 1.0 to 0.0 here
_imageView.alpha = 0.0f;
} completion:^(BOOL finished) {
// Once the animation is completed and the alpha has gone to 0.0, hide the view for good
_imageView.hidden = YES;
}];
}
Do I create a #property (strong, nonatomic) IBOutlet UIImageView *imageView; connected to the image?
You're using storyboards, so control-drag the UIImageView into your interface. The property need not be strong--it should read: #property (weak, nonatomic) IBOutlet UIImageView *imageView.
If you don't know how to control-drag, this video may help: https://www.youtube.com/watch?v=xq-a7e_l_4I. Fast-forward to 2:05.
Open the assistant editor
and ctrl-drag form the UIImageView to the top of your file to make an IBOutlet called imageView. You can invoke (call) your method in one of these ways:
If you want to fade the image when someone clicks a button, ctrl-drag from a UIButton to the popupImage method to make an IBAction.
If you want to fade the image programatically, just do [self popupImage] from wherever in your code you want the fade to begin (in viewDidLoad, for example). In this case, you don't need the IBAction part of your method, and can just call it - (void)popupImage.
Since you want to show your image from the beginning, you should not have it set to hidden.

Auto Layout constraint change does not animate

I was learning the auto layout with animations from the tutorial
http://weblog.invasivecode.com/post/42362079291/auto-layout-and-core-animation-auto-layout-was
and things were working perfect.
When I tried to use this concept in my application, trying to animate a settings screen(a UIView) from bottom to top,it works great when the settings screen is just an empty UIView,
But in case I add a UILabel as a subview to this settings screen, the animation just vanishes.
On removing this UILabel form the settings screen, the animation is visible.
Here are the outlets that I have connected
__weak IBOutlet UIView *settingsView;
__weak IBOutlet NSLayoutConstraint *settingsBottomConstraint;
__weak IBOutlet NSLayoutConstraint *settingsViewHeightConstraint;
View did load setup method(setupViews)
-(void)setupViews
{
settingsBottomConstraint.constant = - settingsViewHeightConstraint.constant;
[settingsView setNeedsUpdateConstraints];
[settingsView layoutIfNeeded];
isSettingsHidden = YES;
}
Hide/Unhide Method
- (IBAction)showSettingsScreen:(id)sender {
if (isSettingsHidden) {
settingsBottomConstraint.constant = 0;
[settingsView setNeedsUpdateConstraints];
[UIView animateWithDuration:.3 animations:^{
[settingsView layoutIfNeeded];
}];
}
else{
settingsBottomConstraint.constant = - settingsViewHeightConstraint.constant;
[settingsView setNeedsUpdateConstraints];
[UIView animateWithDuration:0.3 animations:^{
[settingsView layoutIfNeeded];
}];
}
isSettingsHidden = !isSettingsHidden;
}
My issue seems similar to the
Issue with UIView Auto Layout Animation
I found the answer.
Instead of,
[settingsView layoutIfNeeded];
this line made it worked like charm,
[self.view layoutIfNeeded];
I suppose we need to perform layoutIfNeeded method on the parent view not just the view we are trying to animate.
UPDATE:
As pointed out in a comment by codyko, this is required for iOS 7, iOS 10.
For iOS 8 this issue does not exists.

Fade UIBarButtonItem When Swapped

When I change my UIBarButtonItems they change abruptly, unlike the default which gives a nice but speedy fade animation. You can see this when segueing between view controllers, for instance, the back button will fade in and out. How can I simulate the same effect?
Update - Based on this answer - https://stackoverflow.com/a/10939684/2649021
It looks like you would have to do something like this to make the button itself fade out.
[self.navigationItem setRightBarButtonItem:nil animated:YES];
And do something like this to make it fade in
[self.navigationItem setRightBarButtonItem:myButton animated:YES];
Otherwise if you want more control over animation properties you would have to create a custom view I believe.
EDIT: I just confirmed that you can fade a UIBarButtonItem custom view using this.
As a test I created a simple project and dropped a UIBarButtonItem onto the navigation bar. I created an outlet to the view controller. In viewDidLoad on the view controller I setup a custom view
-(void)viewDidLoad{
[super viewDidLoad];
UILabel *lbl = [[UILabel alloc]initWithFrame:CGRectMake(0,0,40,40)];
lbl.text = #"test";
UIView *customView = [[UIView alloc]initWithFrame:CGRectMake(0,0,40,40)];
[customView addSubview:lbl];
self.barButtonItem.customView = customView;
}
As a test in viewDidAppear I animated it
-(void)viewDidAppear:(BOOL)animated
{
[UIView animateWithDuration:3.0
delay:3.0
options:UIViewAnimationOptionCurveEaseOut
animations:^{
self.barButtonItem.customView.alpha = 0;
}
completion:^(BOOL finished) {
NSLog(#"animation complete");
}];
EDIT: Here's a link to Apples Documentation for a full explanation of UIView animations.
https://developer.apple.com/library/ios/documentation/windowsviews/conceptual/viewpg_iphoneos/animatingviews/animatingviews.html
You might have to create a custom bar button item using a view or an image, and then animate the properties of the view as digitalHound shows.

iOS - Trying to fade a view controller in

In fading a view controller in from black, I am doing the following within viewDidLoad:
Creating a UIView with a black background;
Giving the UIView an alpha value of 1.0f;
Adding the UIView as a subview of [self view];
Fading the black UIView out via animateWithDuration by changing its alpha value to 0.0f; and
Removing the black UIView from [[self view] subviews]
More often than not, this works as planned. Occasionally, however, I see a glimpse of the view controller I want initially hidden, just before the black UIView is drawn.
Is there a way to avoid this? Is there a better method to place this code in than viewDidLoad?
Many thanks
Yes, add the view in the loadView method and do the actual animation in viewDidLoad or viewDidAppear. Or do as the above commentor said and simply use the view alpha.
I would create the UIView that I want hidden in UIViewController's nib file, then link that to via an IBOutlet
#interface SomeViewController: UIViewController
{
IBOutlet UIView *blackView;
}
then in UIViewController's -(void) viewDidLoad; method, I would do the following
- (void)viewDidLoad
{
[super viewDidLoad];
// Fade the opacity of blackView over 1 second,
// then remove it from the view controller.
[UIView animateWithDuration:1
delay:0
options:UIViewAnimationOptionCurveEaseOut
animations:^{
blackView.layer.opacity = 0;
}
completion:^(BOOL finished) {
// This line prevents the flash
blackView.layer.opacity = 0;
[blackView removeFromSuperview];
}];
}

Resources