I'm working on profile screen, there is a UITableView inside the ViewController and I placed all user info inside the UITableView Header. To make screen more accurate due to different sizes of "About" label I use Autolayout with this code:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
sizeHeaderToFit()
}
func sizeHeaderToFit() {
let headerView = tableView.tableHeaderView!
headerView.setNeedsLayout()
headerView.layoutIfNeeded()
let height = headerView.systemLayoutSizeFitting(UILayoutFittingCompressedSize).height
var frame = headerView.frame
frame.size.height = height
headerView.frame = frame
tableView.tableHeaderView = headerView
}
Everything works fine, but the last string of About label is not showing, text interrupts (I set word wrap):
Add a height constraint on tableview header and try to change height constraint where you are changing frame. As you are using autolayout so you should play with the constraints rather than playing directly with the frames
you can follow this tutorial
https://useyourloaf.com/blog/variable-height-table-view-header/
Hope it will help you.
Related
In my application I have a UITableViewController that allows preview of a photo and description to that photo, which are both contained in the UITableView's header. The description label needs to be multiline-compatible, so the lines amount is set to 0, obviously the next problem is to make the UITableView header dynamically resizable to adjust it's size to the amount of text in the description label.
The description label is set to fit it's content with self.descriptionLabel.sizeToFit()
The UITableView header view is also set to dynamically resize to fit it's contents via the widely accepted answer from this post:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if let headerView = tableView.tableHeaderView {
let height = headerView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize).height
var headerFrame = headerView.frame
//Comparison necessary to avoid infinite loop
if height != headerFrame.size.height {
headerFrame.size.height = height
headerView.frame = headerFrame
tableView.tableHeaderView = headerView
}
}
}
This solution resizes the UITableView header view, but for some reason gives my description label absolutely huge margins stretching up and down from the text. I highlighted my description label with self.descriptionLabel.backgroundColor = .red to be sure it's the description label that stretches and that indeed seems to be the case. I tried a multitude of other solutions, but this is the only one that actually at least resizes the UITableView header view, so I'm stuck with this at the moment.
The margins, however, are absolutely enormous and I can't find a solution to make them fit the description label text size. Any help will be greatly appreciated, because I can't get my head around it.
I added screenshots displaying the problem at the end of this post.
This is the top of the UITableView header, with the red displaying the UILabel beginning to stretch down
This is the actual text of the UILabel
And finally this is where the UILabel stretching finishes with the UIButton at the bottom. I am at a complete loss of how to fix this.
This is my header view UI in Interface Builder
And these are the detailed constraints of my description label in Interface Builder
I believe since the translatesAutoresizingMaskIntoConstraints ARE set to false for the headerView the layout is not auto adjusted once it's calculated in layoutSubviews method.
Try setting the translatesAutoresizingMaskIntoConstraints to true to set the headerView height properly as below:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if let headerView = tableView.tableHeaderView {
let height = headerView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize).height
var headerFrame = headerView.frame
//Comparison necessary to avoid infinite loop
if height != headerFrame.size.height {
headerFrame.size.height = height
headerView.frame = headerFrame
tableView.tableHeaderView = headerView
}
}
translatesAutoresizingMaskIntoConstraints = true
}
i have a scrollview which has a picture, text, button, label and then a collectionView whose number of rows is dynamic in nature. Its like collectionview will grow in height and hence the scrollview should assume collectionView height as well as other elements height to get a smooth scroll. How to achieve this using auto Layout in ios?
So my doubt is how to make a dynamic scrollview height based on a growing colelctionview or tableview height.
You can increase the height of CollectionView Height Constraint , connect Height contains to your ViewController and than .
how to connect constraint to outlet ?
let height = self.collectionView.contentSize.height;
self.heightConstraints = height;
self.scrollView.contentSize = CGSize.init(widht:self.scrollView.frame.size.width,height:height)
FOr Swift 4.2
override func viewDidLayoutSubviews() {
let heightFilterCOll = self.filterCollectionView.contentSize.height
self.filterCOllectionViewCOnstraintHeight.constant = heightFilterCOll
self.ScrollView.contentSize = CGSize(width:self.ScrollView.frame.size.width,height:heightFilterCOll + 77)
}
These methods didn't work for me. Try,
self.collectionView.reloadData()
DispatchQueue.main.async {
self.heightCollectionViewConstraint.constant = self.collectionViews.collectionViewLayout.collectionViewContentSize.height
}
func setTableHeader(){
let headerWidth = Double(tableHeader.frame.width)
// also tried let headerWidth = Double(tableView.frame.width)
print("header width is \(headerWidth)")
}
func viewWillAppear(){ output --> 351
setTableHeader()
//also tried in View Did Appear
}
func viewDidDisappear(){ output --> 296
setTableHeader()
}
The outputs refer to what occurs when run on Iphone SE. I designed my tableview and table header with constraints in Storyboard with the Iphone 6 display. I was able to get the result I wanted by changing setTableHeader to reflect view.frame.width - (left and right constraints from storyboard), however I was wondering why I couldnt get this to work, and what the less hacky work around would be? Also I am in actuality setting the dimensions of table header's subviews inside setTableHeader, but these subviews have no constraints (programatically nor in storyboard), in case that is relevant.
Thank you.
Try this , The solution was to override UIViewController().viewDidLayoutSubviews(), get the proper size of the header view based on it’s constraints, set the frame on the header, and reset it as the table header view
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// Dynamic sizing for the header view
if let headerView = tableView.tableHeaderView {
let height = headerView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height
var headerFrame = headerView.frame
// If we don't have this check, viewDidLayoutSubviews() will get
// repeatedly, causing the app to hang.
if height != headerFrame.size.height {
headerFrame.size.height = height
headerView.frame = headerFrame
tableView.tableHeaderView = headerView
}
}
}
Please try to add this code to viewDidLayoutSubviews method.
All views got their actual sizes only alter layout. Method viewDidLayoutSubviews called before viewDidAppear and after viewWillAppear.
I have just tried below lines of code, but I doesn't work correctly. I wonder that how can I provide this case for header or footer programmatically, may be using autolayout I don't know exactly which one solved my problem. I'm using xib file both of UITableViewHeaderFooterView.
If someone explain I would be great.
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// Dynamic sizing for the footer view
if let footerView = tableView.tableFooterView {
let height = footerView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height
var footerFrame = footerView.frame
if height != footerFrame.size.height {
footerFrame.size.height = height
footerView.frame = footerFrame
tableView.tableFooterView = footerView
}
}
}
The UITableView calculates the HeaderFooter before they displayed, you can't update that height without calling reloadData() again.
Have you tried to use AutoLayout on those HeaderFooterViews?
I would set up the view from xib with the right constraint, and then:
self.tableView.estimatedSectionHeaderHeight = 100
self.tableView.sectionHeaderHeight = UITableViewAutomaticDimension
I'm trying to create a UITableView with a header view using autolayout using storyboards. It looks fine in Xcode, but when I run the app, it does not look the same.
In Xcode:
In the app:
The image has a constraint for 150x150, and there are 8-high constraints between the top-image, image-middle label, middle description-label and description label-bottom.
Both labels have numberOfRows set to 0 and lineBreakMode set to ByWordWrapping.
I have tried settings the frame via:
if let headerView = self.tableView.tableHeaderView {
headerView.setNeedsLayout()
headerView.layoutIfNeeded()
let height = headerView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height
println("Setting height to \(height)")
var headerFrame = headerView.frame
headerFrame.size.height = height
headerView.frame = headerFrame
self.tableView.tableHeaderView = headerView
}
One of the original issues was that I had some erroneous constraints (that for some reason Xcode only started complaining about today), so I have removed those and set a contentHuggingPriority of 252 (higher than all others) on the app name label. When I resize the header view manually in the storyboard the image and app name label stay the same height, and the description label grows. It would appear that the apps uses the size of the header in the storyboard at run time, and doesn't get the height from its children.
Answering my own question here:
There are 2 steps that seem to get this to work. The first is in ViewDidLoad, and the second is in viewDidLayoutSubviews:
var headerView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
if let currentTableHeaderView = self.tableView.tableHeaderView {
currentTableHeaderView.removeFromSuperview()
}
// Setting the table header view with a height of 0.01 fixes a bug that adds a gap between the
// tableHeaderView (once added) and the top row. See: http://stackoverflow.com/a/18938763/657676
self.tableView.tableHeaderView = UIView(frame: CGRectMake(0, 0, CGRectGetWidth(self.tableView.frame), 0.01))
self.headerView = AboutTableViewHeaderView(frame: CGRectZero)
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if let tableHeaderView = self.headerView {
var frame = CGRectZero
frame.size.width = self.tableView.bounds.size.width
frame.size.height = tableHeaderView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height
if self.tableView.tableHeaderView == nil || !CGRectEqualToRect(frame, tableHeaderView.frame) {
tableHeaderView.frame = frame
tableHeaderView.layoutIfNeeded()
self.tableView.tableHeaderView = tableHeaderView
}
}
}
Hopefully that all makes sense. The viewDidLayoutSubview code is via http://osdir.com/ml/general/2014-06/msg19399.html