Swift adaptive cell height in static tableview - swift

I am creating a static tableview to as my page will have a mixture of text and images in different rows.
Here is an example. This was created in obj c webView, but i want to use Swift and be native, no webview
Here is the code in my tableViewController:
import UIKit
class AdaptiveRowTableViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
self .tableView.rowHeight = UITableViewAutomaticDimension
self .tableView.estimatedRowHeight = 44
}
override func viewDidAppear(animated: Bool ) {
tableView.reloadData()
}
}
I have set the row height to 0.
I have tested with a label and an image. The label works fine, but the image's row is not adjusting correctly.
Here is the result.
Any ideas on how to fix the image row height?

There is a nice apple video where you can find how to create adaptive cell height from minute 24.
You have to create constraints between the text and image and the cell and create relationships between them. Basically set a top and bottom constraint between text and cell and create a height relationship between text and image.

Related

get height of a tableView

I have a tableView between a label which is on top (constraints: align center x, align top to 20).
A button is on the bottom (constraints: align center x, align bottom to 50).
And the tableView is aligned between those two objects by top/bottom to 20.
I am trying to read out the height of the tableView, because depending which device I use the height should differ?
But if I use in my code the following, I always get the same height for the tableView.
The print result is always 616.
What am I missing/not understanding correctly?
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
print(tableView.frame.size.height)
}
Try this method
override func viewWillLayoutSubviews() {
super.viewDidLayoutSubviews()
print(tableView.frame.size.height)
}
The reason that you see two different values printed is because this method is called right after viewdidload and once again after all the auto layout or auto resizing calculations on the views have been applied. Meaning the method viewDidLayoutSubviews is called every time the view size changes and the view layout has been recalculated.
For more info on this refer to
Apple documentation on viewdidlayoutsubviews
try getting your height in
override func viewWillLayoutSubviews() {
print(tableView.frame.size.height)
}
When your view controller is created from a storyboard, all initial frames are equal to your storyboard selected ones, so they will be correct only to device selected in the storyboard
First time you can access real frames is after first layoutSubviews, so you need this:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
print(tableView.frame.size.height)
}
Check out more about view lifecycle here
p.s. newer forget to call super. method when you're overriding something, you may break something easily. Unless the documentation says so or you're really knowing what you're doing

Best way of determining what the maximum possible width of a collection view cell is based the size of a label?

I'm running into the following issue:
I have a horizontal scrolling collection view.
I require all my collection view cells to be the exact same width. This is a requirement from a designer.
My collection view cells simply have a label in a subview that must be centered horizontally and vertically (and at least 20px from the top/bottom and sides). The label is 1 line always.
In order to determine the maximum width is, I thought I would setup a cell offscreen and cycle through each of my strings. I would call prepareForReuse on the cell to set it back up for the next string. For example:
for viewmodel in vms {
cell.setupCell(cellViewModel: viewmodel)
cell.layoutIfNeeded()
print("Size = \(cell.frame.size.width)")
cell.prepareForReuse()
}
The Size = always prints 144 (which is the width of the cell in the .xib).
Once the app is running though, the cells have all different widths.
class CollectionViewCell: UICollectionViewCell {
#IBOutlet var titleLabel: UILabel!
#IBOutlet var backgroundImageView: UIImageView!
func setupCell(cellViewModel: CellViewModel) {
titleLabel.text = cellViewModel.title
}
override func prepareForReuse() {
self.titleLabel.text = ""
self.backgroundImageView.image = nil
}
}
How do I calculate this width properly before hand, so I can set them all size widths to the largest width (to ensure all my content is showing properly).
If it makes a difference, my collectionView here inside a tableview and my CollectionViewCell has an inequality width constraint of >144 (it currently grows to show all content).

Automatic height adjustment for static UITableViewCell doesn't work

I have a static UITableView and I want to set the row height for three of the cells dynamically. So in viewDidLoad() I implemented the following code:
tableView.estimatedRowHeight = 100
tableView.rowHeight = UITableView.automaticDimension
I also implemented the heightForRowAt method:
(The first two cells of the first section should have a fixed height)
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.section == 0 && indexPath.row == 0 {
return CGFloat(85)
} else if indexPath.section == 0 && indexPath.row == 1 {
return CGFloat(145)
}
return UITableView.automaticDimension
}
This the result which I'm currently getting:
I changed the lines of the labels to 0, too and the constraints of the labels inside the cells are 0, 12, 0, 12 (top, right, bottom, left).
Does anybody know, why the cell in section 3 doesn't display the data in the right way?
Edit:
(How it looks after the implementation of the suggestion above)
Because sizeToFit() did not work for you, we are going to try something a little more involved.
The cell in section 3 is displaying the data the right way. This is because UILabels don't automatically adjust their height to accommodate the text inside. Here's what you need to do:
1. Create a height constraint for your UILabel In your interface builder, add a constraint for the height of the UILabel in section 3's cell. Connect this height constraint to your view controller's class via an #IBOutlet:
class YourViewController: UIViewController {
#IBOutlet var cellLabel: UILabel!
#IBOutlet var cellLabelHeight: NSLayoutConstraint!
...
}
2. Add String extension that calculates height I am unsure of where/when you are setting the text of the UILabel in question, but I know you are doing this somewhere as you have described it as being "dynamic". Whenever you do set the text of the UILabel in question, you now also need to change the constant of the height constraint that we made in order to accommodate this text. So, we need to be able to calculate the height of the UILabel based on its width and font. We can add an extension to String in order to do this:
extension String {
func height(withConstrainedWidth width: CGFloat, font: UIFont) -> CGFloat {
let constraintRect = CGSize(width: width, height: .greatestFiniteMagnitude)
let boundingBox = self.boundingRect(with: constraintRect, options: .usesLineFragmentOrigin, attributes: [.font: font], context: nil)
return ceil(boundingBox.height)
}
}
3. Set the height constraint's constant based off the UILabel's text The final step is to set the height of the UILabel height constraint we made by using the extension we just created:
cellLabel.text = "DummyDataDummyDataDummyDataDummyDataDummyDataDummyDataDummyDataDummyData"
//This will be called immediately after you set the text for the UILabel in question
cellLabelHeight.constant = cellLabel.text.height(withConstrainedWidth: cellLabel.frame.width, font: cellLabel.font)
The cell in section 3 is displaying the data the right way. Unless you tell it otherwise, a UILabel will not automatically adjust to accommodate the text within it.
What I need you to do is select the UILabel in question, then in the attributes inspector, set the Number of Lines to 0.
You also said that this UILabel is dynamic, meaning you are setting it's text somewhere in your code. Immediately after you set this UILabel's text, you are going to want to call myLabel.sizeToFit(). This should adjust the label's height to accommodate the text within.
If this doesn't work, I have another, more involved solution that should work for you.
Please look at the below;
Select your cellLabel and set the Lines value to 0:
Also apple says Self-Sizing
Summary :
lay out your table view cell’s content within the cell’s content view. To define the cell’s height, you need an unbroken chain of constraints and views (with defined heights) to fill the area between the content view’s top edge and its bottom edge. If your views have intrinsic content heights, the system uses those values. If not, you must add the appropriate height constraints, either to the views or to the content view itself.
Change the bottom constraint of the AuthorLabel from equal to Greater than or equal

Swift, Auto Resize Custom Table View Cells

In my app, I have a table view with an image, label and text view in each cell. I would like to be able to auto-resize the cells depending on the amount of content in the text view. (The text view is the lower most text.)
So far, I have added the correct constraints; leading, trailing, top and bottom to the text view and have disabled scrolling and editing.
In my tableViewController.swift file, I have written this code:
override func viewWillAppear(_ animated: Bool) {
tableView.estimatedRowHeight = 100
tableView.rowHeight = UITableViewAutomaticDimension
}
However, this is not working as when I add more text to the text view, it just cuts off.
Maybe this has something to do with the card like look, I have got a UIView in each cell acting as a card.
I honestly don't know what I am doing wrong
A picture is below of what my app looks like and if anyone could help that would be greatly appreciated
Check if your constraints are like this(based on your image) :
imageView : set to Top and Leading of your container, with fix height and width values.
label : you can set it to top and horizontal space of your image, with fix height and width as well.
textView : leading to image, top space to label, trailing and bottom to container.
And keep using
tableView.estimatedRowHeight = 100
tableView.rowHeight = UITableViewAutomaticDimension
in your viewWillAppear()
Update for swift 4.2
Use:
UITableView.automaticDimension
Instead of:
UITableViewAutomaticDimension
Make sure that the content mode is set to Scale To Fill of your UITextView
Make sure that there are no height constraints for the UITextView and the card UIView
Try to add the estimated height into viewDidLoad:
override func viewDidLoad() {
tableView.estimatedRowHeight = 100
tableView.rowHeight = UITableViewAutomaticDimension
}
Maybe the AutoHeight is not working because of the UIView above the UITextView. Try to call the sizeToFit and layoutIfNeeded methods for the UIView in the cellForRowAt:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Identifier", for: indexPath) as! CustomTableViewCell
cell.vwCard.sizeToFit()
cell.vwCard.layoutIfNeeded()
return cell
}
You can also try the sizeToFit and layoutIfNeeded as well for the UITextView.
Hope this works........
Set bottom of your textView with bottom of that white UIView and make sure that white UIView has left,right,top and bottom constraints :)
Same type of example is explained here programmatically....

Automatically adjust width of a view based NSTableView based on content

Title should read: Automatically adjust width of the containing NSWindow of a view based NSTableView based on NSTableCellView's NSTextField content intrinsic content size.
A bit like this other question, I would like to implement an autocompletion NSWindow with an NSTableView inside it that adjust to the width of the length of the available autocompletions implemented as NSTextField inside an NSTableCellView. Each autocompletion should obviously be displayed on one line...
The previous question has been answered but was only related to the hight of the NSTableView. I would like to know how to do the "same" for the width. I would like to implement the solution as much as possible using auto layout.
I've tried to set the horizontal "Content Hugging Priority" and the "Content Compression Resistance Priority" to the maximum of 1000 for each view element participating in the final display of the NSWindow. I was thinking that the intrinsic content size of the NSTextField would force all other elements to adjust but it does not work.
Setting the NSTableColumn width does not work either since the NSClipView of the NSScrollView is not modified by this width: the NSScrollView adjusts and creates horizontal scroll bars to cover the entire "document".
Here is a link to a sample project to demonstrate the problem:
sample project
Any help would be greatly appreciated!
I fixed the problem using this code with the scrollViewWidthConstraint being an IBOutlet to the NSScrollView width constraint, localTableView being an IBOutlet to the NSTableView and tableColumn being an IBOutlet to the NSTableColumn (the only one in my case).
Note: The linked project on GitHub has been updated with the changes.
override func viewDidLoad() {
super.viewDidLoad()
self.updateTable()
}
func updateTable() {
localTableView.reloadData()
var computedWidth: CGFloat = 0
for var row = 0; row < 10; row++ {
let tableCellView = self.tableView(localTableView, viewForTableColumn: tableColumn, row: row) as! NSTableCellView
computedWidth = max(computedWidth, tableCellView.textField!.intrinsicContentSize.width)
}
scrollViewWidthConstraint!.constant = computedWidth
scrollView.needsUpdateConstraints = true
}