In auto layout, How do I "hide" a UIView? - ios

In my UITableViewCell, I have two UIViews stacked on top of each other. Let's call them Top and Bottom.
The Top view has leading, trailing, and top constraints to superview. It has a height constraint of 20.
The Bottom view has leading, trailing, and bottom constraints to superview. It has a height constraint of 20.
Top and Bottom have a vertical constraint.
What is the easiest way to programatically "hide" the Bottom View (and have the Top View touch the bottom of the superview)? I prefer not to create any more constraints, since I did design this in storyboard, and I prefer not to activate/disable constraints.

If you don’t need to target iOS 8 and below, the easiest way is to embed the two views in a UIStackView. You can then simply hide a view by setting its hidden property and the stack view will automatically update the layout:
The stack view automatically updates its layout whenever views are added, removed or inserted into the arrangedSubviews array, or whenever one of the arranged subviews’s hidden property changes.
Since your parent view is a table view cell, you may have to tell the table view to recalculate the cell heights (unless you’re using autosizing cells, then this may work automatically, I’m not sure). You can force a recalculation by sending the table view an empty beginUpdates/endUpdates pair:
tableView.beginUpdates()
tableView.endUpdates()

The right way:
The Top view has leading, trailing, and top constraints to superview. It has a height constraint of 20.
The Bottom view has leading, trailing, bottom constraints to superview and top constraint to Top view.
Than just make a property for height Constratint inside your cell:
#property (nonatomic, weak) IBOutlet NSLayoutConstraint *heightConstraint;
Than when you need to change the size, call this code:
self.heightConstraint.constant = 40;
[self.view layoutIfNeeded];
or with animation:
self.heightConstraint.constant = 40;
[UIView animateWithDuration:0.3 animations:^{
[self.contentView layoutIfNeeded];
}];

You can increase the height constraint of the top view to 40 and reduce the height constraint of the bottom view to 0. Personally I prefer to have the bottom view height constraint to 20 and add a constraint to the topView bottom equal to bottomView top. And if i want to hide the bottomView I just change the height constraint of the bottomView to 0.
Hope it helps. If you need I can post some pictures in Xcode.

Related

Make UIScrollView with dynamic height subviews work automatically with Auto Layout

I have the following view structure with its constraints:
UIView "parent"
UIScrollView (leading, trailing, top and bottom to superview)
- UIView "container" (leading, trailing, top and bottom to UIScrollView,
equal width and height so parent UIView)
- UIView "A" (leading, trailing, top to UIScrollView, height of 200)
- UIView "B" (top, leading and trailing to UIView A, height of 140)
- UIView "C" (top, leading and trailing to UIView B, height >= 88 "rest
of the screen until bottom", bottom to UIView "container")
"A" and "B" UIView's do not change its size but "C" does. Inside it, I am adding programmatically n "labels containers" UIView that have different heights depending on the content of m UILabel that they host.
Right now, I am calculating the size of the n UILabel with boundingRectWithSize: and I am sizing the height of their parent "labels containers" UIView that it is being added inside "C" UIView setting its height constraint to the sum of all UILabel.
Then, I resize "C" UIView height constraint so that it is equal to the sum of all added UIView.
This is working perfectly on all different screen sizes, portrait and landscape. The UIScrollView is showing all three "A", "B" and "C" subviews, having "C" n UIView that host m UILabel.
But now I am having troubles when rotating the device. I face the problem that I have to recalculate the size of all UILabel to change the height constraint of all the "labels container" UIView and change the "C" UIView height constraint so that it can fit everything without large blank spaces between all views.
So my question is: how can I achieve the same behaviour using exclusively Auto Layout?
Now I have to recalculate sizes and change height constraints so that everything adapts, but I would love that all UILabel resize themselves automatically and fit their content, then the "labels container" UIView resize to fit all the UILabel and then "C" UIView resizes automatically to fit the content.
Thank you in advance!
As per my knowledge you need to add TableView for your dynamic labels and to achieve this you have to follow below steps:
1step : Add ScrollView in your ViewController.
2step : Add ContainerView in ScrollView to manage scroll constrains.
3step : Add your "A" view with fixed size lets say 150px.
4step : Add your "B" view with fixed size lets say 150px.
5step : Add TableView for dynamic labels with fixed size 0px. At this step make Outlet of your tableView height Constrains we will use it in next step.
6step : Call your service and add labels in your tableView.
in this 6th step while you are adding labels in your table view means while you reload your tableView do below code for dynamic heigh constrains.
7step : Now as per your Row height adjust height of table view as mention below.
arrListArray = #[#"One",#"Two",#"Three",#"Four",#"Five",#"Six",#"Seven",#"Eight",#"Nine",#"Ten"];
int rowHeight = 44;
self.tblHeightConstraint.constant = (rowHeight * arrListArray.count);
now reload your constrains with below method:
[UIView animateWithDuration:0.1
animations:^{
// Called on parent view
[self.view layoutIfNeeded];
}];
it will increase your scrollView contain size automatically.
Show sample images :
View Constrains Stack :
Now as per your comment you have to add CollectionView in place of tableView and add TableView in CollectionViewCell with your specific design.
Hope this will helps!
Ok, I was doing three things wrong:
1st: I was calculating the height of the labels to set then the size of the "labels container" UIView using a height constraint. Height constraints not needed as Auto Layout manages everything.
2nd: I was modifying the "C" UIView constraint height manually by adding the height value of each "labels container" UIView added.
3rd: After fixing the first two steps, I forgot to set the last added UIView constraint with its parent view...
Now everything works as expected.

iOS Autolayout storyboard ScrollView - button bottom of the scrollview is unable to clickable

Using Storyboard, in UIViewController using UIScrollView, UIView as content view
Scrollview Constraints - top, bottom, left, right
UIView as contentview constraints - top, bottom, left, right, equal width height to ViewController's View.
I am using these constraints, can anyone please help me out why button is not calling?
The button is not clickable because it is below the frame of the content view. You need to remove all auto layout constraints from your content view (the UIView inside the scrollview).
Then you can add all the objects that you need to add to the content view and set the height of the content view according to the height of the content.
So lets say that you calculated a height of 1000 for the content of the objects in the scroll view. You would then need to set the frame of the content view like this:
contentView.frame = CGRectMake(0,0,scrollView.frame.size.width, 1000);
And don't forget to set the contentSize for the scrollview so that the scrollview knows how much room it needs to scroll.
Just now found the answer with removing any autolayout constraints, for content view we have to set constraints like below:
Top, bottom, left, right
Align CenterX - here we have to set the content view height then for that constraint we have to set constant as scrollview content size height

UIScrollView does not Scroll completely

I have a ViewController. In it I put ScrollView with the View(contentView). Later I drag from contentView to View and set Equal Height. Now it scrolls, but not fully.
As you see there are it has continue below the textView, but it
doesn't scrolls. How can I fix it?
UIScrollView is able to automatically calculate it's content height and width, but you need to help it with this.
To do so you need to:
Bound contentView (in your case) to all sides of superview (which is Scroll View).
Let contentView to calculate it's sizes. Here is a small mistake in your approach. You've set height of the contentView equal to View's height. So basically Scroll View's contentSize.height is the same as View's height. Which is not really what you want with dynamic content.
Usually you want to set width of the contentView equal to View's width and do not set contentView's height. Instead you want to bind subviews of contentView to their superview in such a way that their superview (contentView) will calculate it's height automatically.
In your case I would bind:
pizza.jpg to left-top-right of superview (height of pizza.jpg will be set from intrinsic image size);
SAMPLE TITLE label - left-right to superview; top to pizza.jpg image;
Text View - left-bottom-right to superview; top to SAMPLE TITLE label; set a fixed height.
In this case contentView will define needed height by itself. Scroll View will set it's contentSize accordingly.
And your screen will be able to scroll vertically (it should be) ;)
You need to set the contentsize of the scrollview. Use the below code to do that:
func viewDidLayoutSubviews()
{
super.viewDidLayoutSubviews()
self.scrollView.contentSize = CGSizeMake(self.view.frame.size.width, self.contentView.frame.size.height);
}
To use Autolayout with UIScrollView is tricky.
In your code you have to update height constraint for your contentView by calculating height of subviews of contentView and that will automatically update the contentSize for your ScrollView and you can scroll through all subviews.
For more info to use Autolayout+UIScrollView your can read this.
According to this link (thanks to this Matt's answer first), UIScrollView acts differently with AutoLayout than the other views.
Subviews of a scrollView set their constraints from the contentView of the scrollView and not the scrollview directly. This allows the content to scroll.
So :
Add a UIView to your scrollView, this will represent the contentView of your scrollView. Add constraints to top, bottom, trailing, leading from the view to its superView
Interface Builder complains. Here you see the different between a basic view and a scrollView. The reason is a contentView has to be fill to know its size. So add a equal width from the contentView to the scrollView
The contentView knows now its width but not its height. So add your labels and your UIImage as subviews of the contentView. Add constraints from bottom to the top. Don't miss to add a height constraint to the UIImageView.
It should look like this :
Hope this helps
Read this (from Matt once again) for further informations

[Auto layout]Attaching UIView to the bottom of its superview while superview's height is changing

I have a superview which is just a subclass of UIView, and I have a subview which is a subclass of UIImageView that I want to attach to the bottom of the superview.
The height of the subview is fixed, but the height of the superview is subject to change. So basically, I want the subview to always attach to the bottom of the superview while I change the height of the superview programatically.
I'm doing it by Auto layout,
So superview has left,top,right attached to its superview, and a fixed height(I gonna change it programatically), here's its constraints,
And the subview has left, bottom, right attached to the superview, and its fixed height, and another constraint that superview's height should equal or greater than the subview's height.
Finally, when I tap the button at the very bottom, I change the height of the superview. Here's the code,
- (IBAction)testButtonPressed:(id)sender {
[self.dragDownView setFrame:CGRectMake(CGRectGetMinX(self.dragDownView.frame), CGRectGetMinY(self.dragDownView.frame), CGRectGetWidth(self.dragDownView.frame), 100)];
}
However, it's not doing what I wanted, which is keep the subview attached to the bottom of the superview.
Before I change the height:
After I change the height:
As you can see the height of the superview is changed, however the subview still keeps what it was before.
Anyone who can help me?
link constraint:
update view's frame like this:
self.heightConstraint.constant = 320;
[self.view layoutIfNeeded];
As you are using Autolayout Constraint you should update Constraint instead of Frame.
Link Height constraint of your Superview to IBOutlet as #mistyhua suggested.
Now when you what to change Height of your Superview then instead of changing frame of Superview change Height Constraint value.
self.heightConstraint.constant = 320;
[self.view layoutIfNeeded];

Remove UIView from superview programmatically (autolayout)

I have an UIViewController that contains the main UIView and inside of this are a small UIView on the top and a UITableView that fills the rest of the space.
All the design has been done with Storyboards and autolayout, so basically there are these constraints for the upper UIView:
Top space = 0px to superview
Leading space = 0px to superview
Trailing space = 0 px superview
Height = 44px
And these for the UITableView:
Top space = 0px to UIView
Bottom space = 0px to superview
Leading space = 0px to superview
Trailing space = 0 px superview
Everything works fine and resizes properly when using a different screen size or orientation. What I am trying to do now is deleting the top UIView programmatically and then I want the UITableView to fill the space to the top of the superview.
I know I could create programmatically a new constraint for the UITableView, but what I am looking for is for a low-priority-constraint? already defined in the Storyboard that can coexist with the ones already defined before.
Any other trick or workaround would be also appreciated, the only restriction is that everything should be designed in the Storyboard and everything should work after calling:
[view removeFromSuperview];
Here is the design:
just update the tableview's frame to fill the entire window after you removed the top view from it's superview
You only need to add another top constraint, one to the top layout guide, and then edit it to have a priority of 900, and a constant value of 0. If you already have the top view in place, you'll have to drag from your lower view to the main view in the list on the left since you won't be able to access the main view in the canvas.
Its very easy, as you have already made Height constraint for top UIView and vertical space constraint between top view and table view.
Create instance of Height constraint in respective implementation (.m) class.
#property (strong, nonatomic) IBOutlet NSLayoutConstraint *topViewHeightConstraint
then when you don't want top view, write topViewHeightConstraint.constant = 0.f
As you have already made vertical space constraint between top view and table view, table view will take whole space of super view.
When you want top view again just set constraints value.

Resources