I have a ViewController that is divided in 2 parts.
The top is a UIWebView
The bottom is a UITableView
Sometimes, there is no content required for the UITableView. So what I would like to do is have the UIWebView expand into the empty space the UITableView has relinquished.
I have Auto Layout Enabled with the following constraints:
The UIWebView is pinned to the top of the ViewController and the bottom of the UIWebView is pinned to the top of the UITableView
The UITableView is pinned to the bottom, with the top of the UITableView pinned to the bottom of the UIWebView.
When I set the hidden property of the UITableView to YES, it successfully hides the UITableView, but leaves a void where it once was, not expanding the UIVWebView.
What do you suggest?
Thanks
[EDIT]
The following code pushes down the tableView, but leaves a void behind it.
CGRect newFrame = tableView.frame;
newFrame.origin.y += 130;
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.5];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
[UIView setAnimationDelegate:self];
tableView.frame = newFrame;
[UIView commitAnimations];
I won't "pull" the above UIWebView, it also happens to hide the lower navigaiton bar.
Hiding a view does not change its size or constraints, so the result you get is expected. You should probably have a height constraint on your table view, and make an IBOutlet to it. When there is no content in the table, modify the constant property of the constraint to make it 0.
self.tableHeightConstraint.constant = 0;
When there is content, you can calculate the height you need for the table view, and set the constant to that value, or some maximum value that you don't want to go beyond.
Keep the constraints same as you given with addition to that -
Instead of hiding UITableView , remove it from superview and pinned bottom of UIWebView to bottom with low priority constraints so that when you remove UITableview this low priority constraints will work and it will expand your UIWebView.
Related
I had this structure on my storyboard (i have added some example name to easly understand):
UIView (the main view) "BlackView"
-UIScrollView (inside the main view) "OrangeView"
UIView "YelloView" (ContentView inside main scroll)
UITableView "BluView" (Inside and on the top of the contentView)
UIView "RedView" (Inside of the ContentView and on the same level of UITableview)
What i wanna achive? I want a table that grow proportionally to his rows number (the row height is fixed to 60). I also want an UIScrollview that grow in content_size and scroll ability accordingly to the heights sum of the BlueView and the RedView.
The autolayout constraints are:
UiScrollView "OrangeView": (top 0,trailing 0,bottom 0,leading 0)
UIView "YelloView": (top 0,trailing 0,bottom 0,leading 0) (equal width to main ed equal height to main "BlackView" , priority “low” for bottom)
UITabelView "BluView": (top 0,trailing 0,leading 0)
UIView "RedView": (Vertical space 2 to "BluView",trailing 0,leading 0,bottom 0 to YelloView)
I have a complete chain of constraints from top to bottom of the view. UITableView is free to grow because i haven't set directly his "height" constraint and uitableview setscrollingenabled is FALSE. The result is a tableview that don't grow.
I can produce the growing by code:
Table.frame=CGRectMake(BluView.frame.origin.x, BluView.frame.origin.y, BluView.frame.size.width, BluView.contentSize.height);
I works, the table frame and the "OrangeView" scroll content_size grow correctly but "RedView" doesn't respond to this frame change and it doesn't move to the new "table bottom" ad 2 of distance.
What i have already tried to refresh the constraints system:
[BlackView layoutIfNeeded];
[BlackView setNeedsUpdateConstraints];
[RedView layoutIfNeeded];
[ScrollContainer layoutIfNeeded];
[RedView layoutIfNeeded];
[RedView setNeedsUpdateConstraints];
[OrangeView setNeedsUpdateConstraints];
[RedView updateConstraints];
[OrangeView updateConstraints];
[BlackView updateConstraints];
[BluView setTranslatesAutoresizingMaskIntoConstraints:NO];
[RedView setTranslatesAutoresizingMaskIntoConstraints:NO];
I have called those methods before and after the uitable frame change, they doesn't refresh the RedView's y position. How i can obtain the desired behaviour? There's a way to create anothere type of "costraints tree" or maybe there's another way to refresh the position of the RedView after i have programmatically change the Tableview frame?
UITableView is free to grow because i haven't set directly his "height" constraint and uitableview setscrollingenabled is FALSE.
Setting setscrollingenabled to false doesn't tell the tableView to have the height of its content, it just disables the scroll behavior. So if your tableView is 200pt tall and you have a content of 500pt, you'll never see the 300pt at the bottom.
Add a height constraint to your tableView and update its constant with the tableView's contentSize.height every time the contentSize changes.
This way it will always have the size of its content, and because it's in a scrollView you'll still be able to scroll to see all the content.
PS: The yellow view is useless here if it's only a container for the blue and red views.
How do I set this UIScrollView to focus on the Selected UITextfield at specific points. I want the textfield right above the keyboard and I want to be able to scroll up but not down. My code works except for uiscrollview only lets me scroll down and not up. Any help would be great, thanks.
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.4];
//set Y according to keyBoard height
[self->mainScroll2 setFrame:CGRectMake(0.0,-70.0,320.0,580.0)];
[self->mainScroll2 setContentSize:CGSizeMake(320,780)];
[UIView commitAnimations];
}
As my understanding of your case, you have a UITextfield in the UIScrollView, right?
If this is the case, I recommend you use the property contentInset of UIScrollVIew to "scroll up
For example:
float yourKeyboardHeight = 70.0;//since you are trying to change the scrollview's y to -70
self.mainScroll2.contentInset = UIEdgeInsetsMake(0,0,yourKeyboardHeight,0);
This tells the UIScrollView to create a placeholder behind the contentView. In this code, there are four arguments for the property, it's like UIEdgeInsetsMake(top, left, bottom, right) I just added a bottom inset to the view so that makes the content move up 70.0
Hope this may help
I have a view that automatically adjusts it's height based on number of lines in a UILabel within the view. There is another view which height is pinned to be equal to the view with the label.
I would like to animate the height change caused by setting long text to the label, thus changing the number of lines and causing autolayout constraints to recalculate height. This new height will change the height of the second view too. How can I animate autolayout changes that happen as a side effect of property assignment?
I tried this, but it did not work:
[UIView animateWithDuration:0.3 animations:^{
//I want the side effect of this assignment to be animated
self.viewWithLabel.title = #"This long title will change the view height and cause layout change";
}];
See the documentation
Try:
- (void)viewDidAppear:(BOOL)animated {
[self.view layoutIfNeeded];
[UIView animateWithDuration:1.0 animations:^{
self.viewWithLabel.title = #"This long title will change the view height and cause layout change";
[self.view layoutIfNeeded];
}];
}
I think you want yourTextLabel.clipToBounds = YES also.
If you want more advanced effect, see this question.
I have a UIViewController with a UICollectionView and a UIView at the bottom. The way I put it together is displayed in the image below
The yellow square is the UICollectionView and the red is the UIView. This works out just fine. But now I want to resize the UIView because it sometimes contains more info and needs to be bigger. So I tried this:
[self setFrame:CGRectMake(self.frame.origin.x, self.frame.origin.y, self.frame.size.width, self.frame.size.height + 10)];
But this expands the UIView at the bottom and it is not visible. I guess this is because I do not have the correct constraints? I also tried to subtract the origin.y with the same amount and this works only the UICollectionView doesn't get resized with the new height. So how do I tackle this problem?
If you are using autolayout, you should not be setting the frame from your code. Instead you should modify the constant of a constraint that is causing your view to be the incorrect size. You can have an IBOutlet to that constraint and you can change it's constant property. Then call setNeedsLayout on your view controller's view
When setting constraints on your storyboard or in a xib file, animations perform animations on the constraints instead of the sizes and positions.
First create a outlet reference of the constraint which will change (in your case the top space of your UIView to the top layout guide) in the header file of your view controller.
When you want to animate a view, you now have to update its constraints and ask to layout the views.
For example :
[UIView animateWithDuration:0.2
animations:^{
viewYConstraint.constant -= 44;
[self.view layoutIfNeeded];
}
]
//Now don't forget to update constraints
[self.view updateConstraints];
I've never worked with autolayout constraints before. I have a small new app I'm working on and noticed that the NIB's views are defaulting to autolayout. So, I figured I'd take the opportunity to work with it and try to figure out where Apple is going with this.
First challenge:
I need to resize an MKMapView and I'd like to animate it to the new position. If I do this the way I'm used to:
[UIView animateWithDuration:1.2f
animations:^{
CGRect theFrame = worldView.frame;
CGRect newFrame = CGRectMake(theFrame.origin.x, theFrame.origin.y, theFrame.size.width, theFrame.size.height - 170);
worldView.frame = newFrame;
}];
...then the MKMapView will 'snap' back to its original height whenever a sibling view gets updated (in my case a UISegmentedControl's title is being updated [myUISegmentedControl setTitle:newTitle forSegmentAtIndex:0]).
So, what I think I want to do is change the constraints of the MKMapView from being equal to the parent view's hight to being relative to the top of the UISegmentedControl that it was covering: V:[MKMapView]-(16)-[UISegmentedControl]
What I want is for the MKMapView height to shorten so that some controls beneath the map view are revealed. To do so I think I need to change the constraint from a fixed full size view to one where the bottom is constrained to the top of a UISegmentedControl...and I'd like it to animate as view shrinks to new size.
How does one go about this?
Edit - this animation is not animating though the bottom of the view does move up 170 instantly:
[UIView animateWithDuration:1.2f
animations:^{
self.nibMapViewConstraint.constant = -170;
}];
and the nibMapViewConstraint is wired up in IB to the bottom Vertical Space constraint.
After updating your constraint:
[UIView animateWithDuration:0.5 animations:^{[self.view layoutIfNeeded];}];
Replace self.view with a reference to the containing view.
This works for me (Both iOS7 and iOS8+). Click on the auto layout constraint you would like to adjust (in interface builder e.g top constraint). Next make this an IBOutlet;
#property (strong, nonatomic) IBOutlet NSLayoutConstraint *topConstraint;
Animate upwards;
self.topConstraint.constant = -100;
[self.viewToAnimate setNeedsUpdateConstraints];
[UIView animateWithDuration:1.5 animations:^{
[self.viewToAnimate layoutIfNeeded];
}];
Animate back to original place
self.topConstraint.constant = 0;
[self.viewToAnimate setNeedsUpdateConstraints];
[UIView animateWithDuration:1.5 animations:^{
[self.viewToAnimate layoutIfNeeded];
}];
There is a very good tutorial from apple itself that explain how to use animation with autolayout.
Follow this link and then find the video named "Auto layout by example"
It gives some interesting stuff about autolayout and the last part is about how to use animation.
I have made this small demo available. It shows how auto-layout constraints can be changed and animated in a very simple example. Simply take a look at the DemoViewController.m.
Most people use autolayout to layout items on their views and modify the layout constrains to create animations.
An easy way to do this without a lot of code is creating the UIView you want to animate in Storyboard and then creating a hidden UIView where you want the UIView to end. You can use the preview in xcode to make sure both UIViews are where you want them to be. After that, hide the ending UIView and swap the layout constraints.
There is a podfile for swapping layout constrains called SBP if you don't want to write it yourself.
Here's a tutorial.
No need to use more IBOutlet reference of the constraint instead of this you can directly access or update already applied constraint either applied by Programmatically or from Interface Builder on any view using the KVConstraintExtensionsMaster library. This library is also managing the Cumulative behavior of NSLayoutConstraint.
To add Height Constraint on containerView
CGFloat height = 200;
[self.containerView applyHeightConstrain:height];
To update Height Constraint of containerView with animation
[self.containerView accessAppliedConstraintByAttribute:NSLayoutAttributeHeight completion:^(NSLayoutConstraint *expectedConstraint){
if (expectedConstraint) {
expectedConstraint.constant = 100;
/* for the animation */
[self.containerView updateModifyConstraintsWithAnimation:NULL];
}
}];