Animate UIButton changes location on text change - ios

I'm having trouble changing my button text after animation.
Defined in my .h file
#property (weak, nonatomic) IBOutlet UIButton *btnCheck;
I call this method when i want to animate the button location change
- (void)updateViews {
if(checkedIn){
[UIView animateWithDuration:0.3f
delay:0.0f
options:UIViewAnimationOptionTransitionNone
animations:^{
btnClear.hidden = YES;
[btnCheck setFrame:CGRectMake(90, btnCheck.frame.origin.y, btnCheck.frame.size.width, btnCheck.frame.size.height)];
}
completion:nil];
}else{
[UIView animateWithDuration:0.3f
delay:0.0f
options:UIViewAnimationOptionTransitionNone
animations:^{
[btnCheck setFrame:CGRectMake(20, btnCheck.frame.origin.y, btnCheck.frame.size.width, btnCheck.frame.size.height)];
}
completion:^(BOOL finished){
btnClear.hidden = NO;
}];
}
checkedIn = !checkedIn;
}
That works perfect, pics included below for reference:
The problem is as soon as i try change the name of the button it jumps back to its original frame.
I change the button text in another method like this,
btnCheck.titleLabel.text = #"test";
And as soon as i change that the button jumps back
What's causing the button frame to be reset?
I've tried changing it before the animation,during and on completion. It animates to the new location and jumps back.

This will probabily not answer your question, but I'll show you a better way to change a frame when you want to change only one property in your frame
CGRect buttonFrame = [btnCheck frame];
buttonFrame.origin.x = newXOrigin;
[UIView animateWithDuration:0.3f
animations:^{
[btnCheck setFrame:buttonFrame];
}];
I prefer this method, because you don't have to create a new CGRect and copy paste all the unmodified frame attributes. Ow and you might wanna get the hidden assignment out of the animation block, since that cannot be animated

You should not change UIButton's title that way. Instead, try setting it's title using setTitle:forState: method. Try this, and let me know if this was helpful, Good Luck!

It was Autolayout that caused the problem. Disabled that and everything worked

Related

How can I animate the height constraint of a UIPickerView?

I've learned that the way to animate constraints in Cocoa Touch is to just set them and then put [self.view layoutIfNeeded] in an animation block, like so:
self.someViewsHeightConstraint = 25.0;
[UIView animateWithDuration:0.5 animations:^{
[self.view layoutIfNeeded];
}];
This is working fine, for example with a simple UIView. However, it does not work with a UIPickerView. It just snaps into the new position without animating.
Any ideas why this might be the case? What ways are there to work around this?
The effect I'm going for is that the Picker View should shrink to just show the chosen item, as the user goes on to input other things. One idea I had is to make a snapshotted view and animate that instead, but I couldn't quite get that working either.
I found trying to animate the height or the placement constraint of a UIPickerView to be problematic. However, doing transforms seems to work well -- even if you have Auto Layout Constraints everywhere, including in the view to be transformed.
Here's an example of what works for me. In this case, I've placed the picker view inside a blurring effects view -- but you don't even need to put your picker view inside another view to animate it.
In the code below, when I call show, it animates up vertically. When I call the hide method, it animates downwards.
- (void)showPickerViewAnimated:(BOOL)animated;
{
__weak MyViewController *weakSelf = self;
[UIView animateWithDuration:(animated ? kPickerView_AppearanceAnimationDuration : 0.0)
delay:(animated ? kPickerView_AppearanceAnimationDelay : 0.0)
options:(UIViewAnimationOptionCurveEaseInOut)
animations:^{
weakSelf.pickerViewContainerView.transform = CGAffineTransformMakeTranslation(0,0);
}
completion:^(BOOL finished) {
[weakSelf.view layoutIfNeeded];
}];
}
- (void)hidePickerViewAnimated:(BOOL)animated;
{
__weak MyViewController *weakSelf = self;
[UIView animateWithDuration:(animated ? kPickerView_DisappearanceAnimationDuration : 0.0)
delay:(animated ? kPickerView_DisappearanceAnimationDelay : 0.0)
options:(UIViewAnimationOptionCurveEaseInOut)
animations:^{
weakSelf.pickerViewContainerView.transform = CGAffineTransformMakeTranslation(0, kPickerView_Height);
}
completion:^(BOOL finished) {
[weakSelf.view layoutIfNeeded];
}];
}
picker view, If you have added constraint To TopLayout for yPosition remove it and add constraint to bottom layout instead.
That will solve the problem. here is my code and its working:
self.timePickerHeightConstraint.constant = pickerIsClosed ? 216 :
0;
[UIView animateWithDuration:0.5 animations:^{
[self.view layoutSubviews];
} completion:^(BOOL finished){
}];

Text Field Returns to Original Location after Running Animation

I'm trying to move a text field to the right when a button is pressed. It works fine, however when I click on another text field or any other element the text field re-appears in its current location. I browsed the internet and found it works when I don't have autolayout enabled, however I need autolayout for setting variable positions. Any advice? Here's the method that moves the box:
- (IBAction)EnterInfo:(id)sender {
CGRect newFrame = _UsernameField.frame;
newFrame.origin.x += 500; // shift right by 500pts
[UIView animateWithDuration:1.0
animations:^{
_UsernameField.frame = newFrame;
}];
}
New code for last question:
- (IBAction)EnterInfo:(id)sender {
[UIView animateWithDuration:1.0
animations:^{
_usernameX.constant = 130;
}];
}
If you have auto layout turned on, you can't manipulate the frame like that. You need a reference to a NSLayoutConstraint and update the constant.
like this:
myXConstraint.constant = originalX + 500;
Edit -- and then your animate block should look like this:
[UIView animateWithDuration:0.5 animations:^{
[self.view layoutIfNeeded];
}];

iOS: Animating text position of UIButton doesn't work

I want to have the text of the button 'go away' when pressing a 'wrong answer' button.
In my problem-demo code, my project has two buttons, one with outlet 'myBtn' without any action, and one with TouchUpInside action. The action handler looks like this:
- (IBAction)goPressed:(UIButton*)sender {
//UILabel *lbl = self.myBtn.titleLabel;
UILabel *lbl = sender.titleLabel;
[UIView animateWithDuration:1.0
delay:0.0
options:UIViewAnimationOptionCurveEaseOut
animations:^{
lbl.center = CGPointMake(lbl.center.x-60, lbl.center.y);
lbl.alpha = 0;
}
completion:nil];
}
I am trying to animate two properties: 'alpha' to go from 1 to 0, and position of text to move 60 points to the left.
If I uncomment the first "UILAbel" line and comment the second, then pressing the button runs a nice animation in the second button.
But if I leave the code as it appears, trying to animate the text of the pressed button itself, the alpha is animating fine, but the position is not changing.
Any help would be highly appreciated!
I have seen this kind of problem occurring on iOS7. Animations that worked fine inside an IBAction, don't work on iOS7. I had to move all my animation code to a different method and call the selector after a delay. Your code will work fine if you do this -
- (IBAction) goPressed:(UIButton*)sender {
[self performSelector:#selector(animateButton:) withObject:sender afterDelay:0.1];
}
- (void) animateButton:(UIButton *) button{
UILabel *lbl = button.titleLabel;
[UIView animateWithDuration:1.0
delay:0.0
options:UIViewAnimationOptionCurveEaseOut
animations:^{
lbl.center = CGPointMake(lbl.center.x-60, lbl.center.y);
lbl.alpha = 0;
}
completion:nil];
}
Your problem is mixing up the UIButton with the UILabel.
The method parameter (UIButton*)sender is referencing a UIButton in this case. The reason UILabel *lbl = sender.titleLabel; doesn't work is because the sender is a UIButton reference. To access the label object, you must reference the the UILabel embedded in the UIButton via the hirarchy sender > UIButton > UILabel.
So the code you should use is:
UIButton *button = sender;
UILabel *lbl = sender.titleLabel;
[UIView animateWithDuration:1.0
delay:0.0
options:UIViewAnimationOptionCurveEaseOut
animations:^{
lbl.center = CGPointMake(lbl.center.x-60, lbl.center.y);
lbl.alpha = 0;
}
completion:nil];
}
The reason why the code as it appears behaves strangly is because alpha is a property of both UIButtons and UILabels. So it will work even if you are incorrectly refenrencing the sender.

make a UIButton imageView Bigger than the frame and then back to its original size?

I want to make the UIButton image transform from its current size to twice its size and then back to its original size similar to the facebook "like" animation.
I'm using this code but for some reason it is doing the reverse action; i.e. first shrinks and only then getting large again.
What am I doing wrong? It works perfectly on a uiimageView but not on a uibutton
[self.likeButton setClipsToBounds:NO];
CGAffineTransform firstTransform = self.likeButton.imageView.transform;
[UIView animateWithDuration:.15f animations:^{
self.likeButton.imageView.transform = CGAffineTransformScale(firstTransform, 2, 2);
} completion:^(BOOL finished) {
[UIView animateWithDuration:.15f animations:^{
self.likeButton.imageView.transform = firstTransform;
}];
}];
Layers have a property masksToBounds and UIView has clipsToBounds. Most likely the button has these set to YES on the primary view or subviews. Its possible you can discover which ones have these set to YES, and set them temporarily to NO.
If anyone is interested I solved it by adding a uiimageview above the button and animate it instead of the button image.
its a hack but its working.
//set button.masktobound=NO
[UIView animateWithDuration:.15f animations:^{
self.likeButton.imageView.transform = CGAffineTransformMakeScale(2.0,2.0);
} completion:^(BOOL finished) {
[UIView animateWithDuration:.15f animations:^{
self.likeButton.imageView.transform = CGAffineTransformMakeScale(1.0,1.0);
}];
}];
//Try this

iOS UIView setFrame animation error

I am having a weird error while animating a couple of view in iOS. My goal is to switch from a custom "Split View". You can see what's going on in this youtube video: http://youtu.be/ZWbf2bQYMns
You can see the weird "bump" in the Y value of the UIImageView, and I have been wondering how to fix it for quite a while now.
This is the View Controller's interface:
#interface VideoSharing_Pad : UIViewController
{
IBOutlet UIView *videoCallView;
IBOutlet UIImageView *imageView; //This is "inside" mediaView
IBOutlet UIView *mediaView;
CGRect mediaRect;
CGRect videoCallRect;
CGRect imageRect;
}
In viewDidLoad I store both views doing:
//Get frames from XIB
mediaRect = mediaView.frame;
videoCallRect = videoCallView.frame;
imageRect = imageView.frame;
And this is the code that executes when I want to switch from the Split View to a full Screen Mode:
- (IBAction)toggleFullScreen:(id)sender
{
if (iScreenMode == callAndShareMedia) {
CGRect fullScreenRect = CGRectMake(0, 0, 1024, 768);
CGRect dissapearRect = CGRectMake(0, - videoCallView.bounds.size.height, videoCallView.bounds.size.width, videoCallView.bounds.size.height);
[UIView animateWithDuration:1.0
delay:0.1
options: UIViewAnimationCurveEaseOut
animations:^{
[videoCallView setFrame:dissapearRect];
[imageView setFrame:fullScreenRect];
[mediaView setFrame:fullScreenRect];
}
completion:^(BOOL finished){
}];
iScreenMode = onlyShareMedia;
return;
}
else if (iScreenMode == onlyShareMedia)
{
[UIView animateWithDuration:1.0
delay:0.1
options: UIViewAnimationCurveEaseOut
animations:^{
[videoCallView setFrame:videoCallRect];
[mediaView setFrame:mediaRect];
[imageView setFrame:imageRect];
}
completion:^(BOOL finished){
}];
iScreenMode = callAndShareMedia;
return;
}
}
I would really appreciate any help I can get. Thanks a lot!
this is a screenshot of the XIB:
as you can see from the screenshot and the .h file, the imageView is inside an UIView called mediaView, The other UIView, videoCallView is the one with the three dummy pictures.
Interesting question indeed. It definitely has to do with animating superview and subview at the same time. I did sample program, and reproduced similar situation.
My workaround would be to avoid animating the superview (mediaView), and expand only the subview (imageView) to full rectangle. Since your superview (mediaView) does not have much, it should not give so different user experience.
So, instead of
[UIView animateWithDuration:1.0
delay:0.1
options: UIViewAnimationOptionCurveEaseOut
animations:^{
[videoCallView setFrame:dissapearRect];
[imageView setFrame:fullScreenRect];
[mediaView setFrame:fullScreenRect];
}];
You can do
[UIView animateWithDuration:1.0
delay:0.1
options: UIViewAnimationOptionCurveEaseOut
animations:^{
[videoCallView setFrame:dissapearRect];
[imageView setFrame:(CGRect){fullScreenRect.origin.x - mediaRect.origin.x, fullScreenRect.origin.y - mediaRect.origin.y, fullScreenRect.size}];
}];
For coming back to normal mode, you can just ignore mediaView animation. Probably you want to move (animate) the toggleButton along with other animation as well.
#jrturton's answer (second part) seemed a nice workaround, but it did not work on my sample code. It worked on the way to go (expansion), but bumped on the way back (shrink), for the reason I don't know why. But don't dismiss his answer because of my comment, it could be me.
Interesting question. I can't view your video from work but I expect your issue is that you are resizing both a view and its subview during an animation, there will probably be interference from any autoresizing masks (do you have them?) - the superview will change the size of the subview, then the interpolated frame will be applied.
If you think about it there will also be a stage where your image view has to animate more quickly than the superview as it has more ground to cover to get to the same final rect. The interpolation worked out by the animation may struggle with this.
If removing any autoresizing masks doesn't work, you might need to split the animation into two - one to increase the size of the superview, and another to then zoom the image view to full size.

Resources