Objective C: how to resize uitextview height with animation? - ios

I have UITextView (textView) in some other view (extView) in my Objective C project with some text in it. The text in textView is quite long so it could by maximised and minimised. Of course, I'd like to do it with some animation.
I change the height of extView with code:
- (void)setExtViewHeight:(CGFloat)newHeight withAnimation:(CGFloat)duration
{
[self setNeedsUpdateConstraints];
[UIView animateWithDuration:duration
animations:^
{
self.extViewHeight.constant = newHeight;
[self layoutIfNeeded];
[self.textView layoutIfNeeded];
}
completion:^(BOOL finished)
{
[self layoutSubviews];
}
];
}
My problem is that animation are actually works only for extView. So when I try to minimise my view the textView jumps to new height and after that extView height is changing with animation. This jump of textView is really annoying and doesn't look good.
What did I do wrong? Why height of textView doesn't follow the animation?

Update your autolayout constant outside of the animation block.
Something like this should work.
Edit: As Duncan C. suggested if you don't want to update the textView height constant as well, you will at least need your textView to have top and bottom relational constraints to your extView
- (void)setExtViewHeight:(CGFloat)newHeight withAnimation:(CGFloat)duration
{
self.extViewHeight.constant = newHeight;
[UIView animateWithDuration:duration animations:^{
[self layoutIfNeeded];
} completion:nil];
}

Related

Subviews do not resize properly when animating constraints

I need to change size and position of a subview (call it playerView) of a view of a view controller. I have created properties for constraints I need to change. But when I animate the changes, only playerView is animated, but all of it's subviews are not: their size is changed instantly.
Here's the text:
self.playerViewTop.constant = screenHeight - MinizedPlayerTopOffset;
self.playerViewLeading.constant = MinimizedPlayerOffset;
self.playerViewWidth.constant = MinimizedPlayerWidth;
self.playerViewHeight.constant = MinimizedPlayerHeight;
[UIView animateWithDuration: 2.0 animations: ^
{
[self.view layoutSubviews];
}];
I do not understand why that happens since I use autoLayout. Please help.
You need to call layoutIfNeeded() in the animations block, not layoutSubviews().
(You should actually never call layoutSubviews() yourself. It's a method called by the system during a layout pass and only intended for that purpose.)
[self.view layoutIfNeeded];
[self.subView setNeedsUpdateConstraints];
[self.subView updateConstraintsIfNeeded];
[UIView animateWithDuration:1.0f delay:0.0f
options:UIViewAnimationOptionLayoutSubviews animations:^{
[self.view layoutIfNeeded];
} completion:nil];

AnimateWithDuration doesn't work as expected

I'm trying to run an example to test this function. I have a label an a button in the storyBoard and I have referenced the bottom constraint of the label in the view controller. When I use the button I want the label to move with an animation but it moves without it. Here's the code of the button:
- (IBAction)sd:(id)sender {
[UIView animateWithDuration:0.5f animations:^{
self.constraint.constant += 50;
}];
}
I know how to use it in swift but I'm having problems in objective c and I know it will be just for a little mistake... Any help?
This is not the right way of animating a UI component constrained with Autolayout. You should first update the constraint, then call layoutIfNeeded within the animation block:
self.constraint.constant += 50;
[UIView animateWithDuration:0.5f animations:^{
[self.view layoutIfNeeded];
}];
Use this
self.constraint.constant += 50;
[UIView animateWithDuration:0.5f
animations:^{
[self.view layoutIfNeeded];
}];
Try this setNeedsLayout helps in some cases.
self.constraint.constant += 50;
[UIView animateWithDuration:0.5f
animations:^{
[self.view setNeedsLayout];
}
completion:^(BOOL finished) {
}];

Changing tableview frames with animation using autolayout

i am trying to change tableview frame by using autolayout in animationWithDuration block. Like That;
[UIView animateWithDuration:0.3f animations:^{
weekdayOffersVerticalConstraint.constant = 80;
[headerView layoutIfNeeded];
[weekdayTableView layoutIfNeeded];
self.isTableViewSmall = YES;
} completion:^(BOOL finished) {
}];
my tableview's frames are changing with this code block, but when i scroll to down, cells coming from left side to right side, i thought it is about with [weekdayTableView layoutIfNeeded]; layoutIfNeeded effect to all subviews. How can i obstruct to effect to my tableview's cells?
Sorry for my bad english, Thank you very much for your answers and advices.
Call layoutIfNeeded before you begin the animation to update the constraints:
[headerView layoutIfNeeded];
[weekdayTableView layoutIfNeeded];
[UIView animateWithDuration:0.3f animations:^{
weekdayOffersVerticalConstraint.constant = 80;
[headerView layoutIfNeeded];
[weekdayTableView layoutIfNeeded];
self.isTableViewSmall = YES;
} completion:^(BOOL finished) {
//
}];
You probably also don't want to set that BOOL property inside the animation block unless you have a method that overrides it intentionally during the animation.

Animating constraints is breaking other constraints

I have the following tableview at the bottom of my view
It has a height constraint (priority 250) and a constraint to the bottom of the view (priority 1000). The height constraint points to a `IBOutlet in my view controller.
I want to change the height of the table view from 44.0f to 7*44.0f, so what I am doing is this;
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (self.categoriesShown) {
[self hideCategories];
} else {
[self showCategories];
}
self.categoriesShown = !self.categoriesShown;
}
- (void)showCategories
{
self.categoriesHeightConstraint.constant = self.categories.count * 44.0f;
}
- (void)hideCategories
{
self.categoriesHeightConstraint.constant = 44.0f;
}
It works fine. But when I'm trying to animating all this with the following code:
- (void)showCategories
{
[self.categoryTableView layoutIfNeeded];
[UIView transitionWithView:self.categoryTableView duration:0.3f options:UIViewAnimationOptionCurveEaseOut animations:^{
self.categoriesHeightConstraint.constant = self.categories.count * 44.0f;
[self.categoryTableView layoutIfNeeded];
} completion:nil];
}
- (void)hideCategories
{
[self.categoryTableView layoutIfNeeded];
[UIView transitionWithView:self.categoryTableView duration:0.3f options:UIViewAnimationOptionCurveEaseOut animations:^{
self.categoriesHeightConstraint.constant = 44.0f;
[self.categoryTableView layoutIfNeeded];
} completion:nil];
}
Then the constraints between the tableview and the bottom of the view is somehow broken and this is what I get when I show and then hide the tableview
Does anyone know why, the constraint is broken but only when I try to animate the changes?
Update: UIButton Constraints
Both buttons have width and height constraints as well a a constraint to the bottom of the view. The button on the left has a leading constraint to the view. The one of the right has a trailing constraint to the view. The also both have a horizontal spacing constraint to the table view as mentioned above.
I think your problem is in this method call:
[UIView transitionWithView:self.categoryTableView duration:0.3f options:UIViewAnimationOptionCurveEaseOut animations:^{
self.categoriesHeightConstraint.constant = 44.0f;
[self.categoryTableView layoutIfNeeded];
} completion:nil];
This should do what you're looking for:
self.categoriesHeightConstraint.constant = 44.0f;
[UIView animateWithDuration:0.3f animations:^{
[self.view layoutIfNeeded];
//This is assuming the method is called from a view controller.
//You need to call layoutIfNeeded on the superview of what you're animating
}];
Also, Apple documentation says it's good form to make an extra [self.view layoutIfNeeded] call before you change the constraint so that any incomplete constraint changes and be updated. I'll leave that up to you though.
So I think I got the functionality you're looking for:
I gave the table view a height constraint that matched the top of the buttons, but it could be anything.
Then I get the calculated height the table should be and set it:
tableArray = [[NSMutableArray alloc]init];
[tableArray addObject:#"Row 1"];
[tableArray addObject:#"Row 2"];
etc.......
double newHeight = ([tableArray count] * 44);
CGRect newFrame = CGRectMake(basicTable.frame.origin.x, basicTable.frame.origin.y, basicTable.frame.size.width, newHeight);
[basicTable setFrame:newFrame];
And then for your animation I used [UIView animateWithDuration] as shown:
[UIView animateWithDuration:1.0 delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^{
tableHgtConst.constant = newHeight;
[self.view layoutIfNeeded];
} completion:^(BOOL finished) {
}];
I just left the bottom constraint alone, then changing the height constraint to match the height forces the table up instead of down.
Screens:
Simulator: http://i.stack.imgur.com/T7MBr.png
Code File: http://i.stack.imgur.com/GGOkq.png

UIView automatically moving by uitextfield keyboard

So i have a really weird problem at my hands and hours of search has provided nothing.
I have a uiview containing a uitextfield. Now initially this view is outside of the visible screen with coordinates like x=-500,y=-500.
However in response to a button press this view animates and moves into the center of the screen.
Now whenever i tap on a uitextfield that is the subview of this view.This view moves back to its original coordinates outside the screen.
I have frantically checked my code and there is nothing that is moving the view outside again once its in. Any help in explaining this very unfamiliar behaviour would be really appreciated.
This code moves the view onto the screen
- (IBAction)Register:(id)sender {
//(self.view.frame.size.width/2)-(self.SignUp_Screen.frame.size.width/2);
//self.login_Screen.hidden = YES;
self.blurView.hidden = NO;
//self.SignUp_Screen.layer.zPosition = 5;
NSLog(#"Register");
self.SignUp_Screen.hidden = NO;
[UIView animateWithDuration:0.25 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
self.SignUp_Screen.frame = CGRectMake(35, 50,self.SignUp_Screen.frame.size.width , self.SignUp_Screen.frame.size.height);
} completion:^(BOOL finished) {
}];
}
and these are the delegate methods for the textfield
-(void)textFieldDidEndEditing:(UITextField *)textField
{
NSLog(#"TextFieldEndEditing");
[textField resignFirstResponder];
}
-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
NSLog(#"textFieldShouldReturn");
[textField resignFirstResponder];
return YES;
}
As Wezly hints at, if you are using autolayout, you don't modify the frame directly anymore. That's the old world. You want to have an Outlet / property for the constraint and animate it.
[UIView animateWithDuration:0.25
animations:^{
SignUp_Screen.centerXConstraint.constant = ...;
SignUp_Screen.centerYConstraint.constant = ...;
[SignUp_Screen layoutIfNeeded];
}];
See here and here for more details.
You should not modify frame if you are using auto layout. You should animate view by animating constraint's constant. For example:
NSLayoutConstraint *viewY; //constraint from superview top to view top
viewY.constant = 100;
[self.view setNeedsUpdateConstraints];
[UIView animateWithDuration:0.3f animations:^{
[self.view layoutIfNeeded];
}];
The way i solved this problem was by linking an IBOutlet to the constraint I wanted to change and then animating it's constant value.
.h
#interface ViewController : UIViewController {
IBOutlet NSLayoutConstraint *constraintHandle;
}
.m
[UIView animateWithDuration:0.25 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
constraintHandle.constant = self.view.center.x;
[SignUp_Screen layoutIfNeeded];
} completion:^(BOOL finished) {
}];
Don't forget to link the IBOutlet to your constraint in your storyboard or xib.

Resources