How to create a self sizing grid in a UITableView cell? - ios

I am trying to build a UITableView similar to this. There are some regular cells and I want one cell to be a grid like this. There should be exactly 20 columns, and cells should be square. So they need to have a width and height of UITableView's width / 20. Also UITableViewCell containing all this items should have the height 5 times of this. How do I make this happen?

If you know the exact number of columns and rows, this is easy to achieve without any code, using a storyboard.
Using nested 5 x 4 UIStackViews, each inner stack view containing 20 alternately coloured UIViews, with all stack views Distribution to Fill Equally, and a single cell's Aspect Ratio constraint to 1:1…
Et voila…
Of course, knowing this technique you could easily create the same in code.

Related

How to make UICollectionViewCells with content lined up across cells

I have a UICollectionView that is using flow layout and it is horizontally scrolling. In each cell, I have five subviews (labels and image views). I have an array of model objects, one object per cell, that contains the data to be displayed in each subview in each cell.
Some items can have more content than others (some labels will have more text), but I want all the cells to be the same height. I also want it so that the top of each subview is lined up with the tops of the same subview in the other cells. And if all model objects have a nil value for one of the fields, then the subviews for that field should be left out of each cell.
For example, I have the following image where it shows three cells and the subviews in each cell. For this example, all of the cells have data for subview 1, so it shows up in all of them. But only the first two cells have data for subview 2, so it only shows up in those cell. Likewise, subview 3 only shows up in the first cell because that is the only cell that has data for that subview. Now for subview 4, none of the cells have data for it, so it is completely skipped and there is no space taken up in any cell to render it. Instead, subview 5 is rendered in the place where subview 4 would normally have been rendered and it is only in the third cell because only that cell had data for it.
I also have dashed lines between the subviews showing that they are supposed to be lined up across cells.
Question
So I am just curious what the best way to do something like this is, given these requirements. Could this be done with AutoLayout or do I need to manually layout these subviews?
The only way I can think of doing this currently is to iterate through all of the model objects, try to figure out how tall each subview is and essentially keep track of the tallest height for each subview. And if no cell has data for a particular subview, the height of that one would be zero.
Next, I would turn those heights into computed offsets for each subview, where the computed offset would be the sum of the heights of the subviews above it and the spacing between each subview.
Then, I would try to lay these out manually, I suppose, with the frame of each subview being set to some width (not sure how to calculate the optimal width of each subview) and a vertical position equal to the computed offset of that subview. Or I guess I could do AutoLayout as well where the top constraint on a field is equal to the computed offset for each subview, but is that less efficient?
And then I guess the height of each cell would be just the computed offset of the last item plus its height plus the spacing to the bottom of the cell. So then I would take the max height of all the cells and set all of the cells to the same height.
But I was just curious if there was a better way of doing this or if there was anything that I was overlooking that could simplify things. I would also like this to be as efficient as possible as the collection view could have up to 100 items in it.
You will need to loop through your data, calculating the "max height" for each item.
I'd suggest putting your 5 "views" in a vertical stack view.
As you loop through your data, get the max height for each of the 5 views. Then, when you set your data in each cell, set the height constraint on each of the 5 views (or, set a view hidden if it is nil in all data items).
Then set your collection view's height to the necessary height to fit all the views plus spacing.

Is it possible to use self sizing cells within self sizing cells?

I want to have self sizing cells within a tableview with self sizing cells. But on first initialisation some cells are not correct. After a scroll to the bottom and the cells will display again the cell size is correct. In the screenshot you can see that the top 2 cells have a white space at the bottom and the third one doesn't. They should all look like the third one.
This is the issue in my main project.
Screenshot
The problem with automatically sizing cells inside automatically sized cells is a bit tricky because you have to understand how it works. UITableView works with estimates most of the time. It usually does not calculate the contentSize precisely because to calculate it precisely, it has to first instantiate every cell, layout it and then calculate its size.
The precise values are calculated only for cells that are displayed (visible in current scroll frame).
The tricky part is that the inner cells (inside your outer cell) are not displayed until the outer cell is displayed therefore the outer cell does not have size calculated correctly. Also note that UITableView does not automatically update cell heights unless explicitly said to do so.
The solution, if you really have to do this, is to calculate the height of the outer cell correctly before it is displayed and manually set a height constraint.
If you know the height (from data source), it's easy. If you actually need to calculate the height of the inner table, you can do something like this:
// make the table high enough to display all cells
innerTableHeightConstraint.constant = 2000
// reload table
innerTable.reloadData()
// force layout
innerTable.layoutIfNeeded()
// now the contentSize is correctly calculated
innerTableHeightConstraint.constant = innerTable.contentSize.height
The whole concept is tricky and ideally you should prefer using UICollectionView or table sections. When you are using inner table views, there won't be any cell reuse for the inner tables and your performance will suffer.
You should not wrap UITableView into UITableViewCell, try to use UITableView Sections instead to add an extra depth level to your UITableView.

Attach/Stick a UIButton under the UITableView

This illustration shows what i'm trying to do:
The green list is the UITableView where it dynamically adjust it's height based on the number of items inside of it.
Underneath of the UITableView is a button that should follow the UITableView whenever it changes it's height size.
The UIButton should always be beneath the UITableView whatever the size of the UItableView.
I'm currently using autoresizing for UITableView
I have tried to use Autolayout but it seems i can't still find the answer.
i currently have no constraints in the layout.
This boils down to calculating the height of the table view that perfectly fits the cells. Basically you need to measure the size of every cell, then create a height constraint on the table view, and set its constant to the sum of the cells' heights.
Measuring the height of cells is tricky thought. If you only have a few cells (like in your illustrations), you can just instantiate all of them, keep them in an array and use systemLayoutSizeFittingSize to calculate their sizes. If you use multi-line labels, it is also important to set their preferredMaxLayoutWidth to appropriate values.
However, if you have only a few cells (and so cell reuse is not important), stack view is probably a better choice than table view. It's just too tricky to calculate the perfect height of a table view.

Nested UITableViews with autolayout

I've got a layout with nested UITableViews (each UITableViewCell's contentView has as unique child another UITableView).
All the leaf cells are correctly set up with autolayout (in fact, when they are presented in a single table they are displayed ok).
But when they are inside the inner table, the outer table does not calculate the correct heights for cells, leading to their standard height of 44. I'm using
self.tableView.rowHeight = UITableViewAutomaticDimension;
self.tableView.estimatedRowHeight = 260;
for both inner and outer tables.
How can I get the tables to show correct heights with autolayout? (I don't want to override tableView:cellForRowAtIndexPath:, I want autolayout to do the trick).
Thank you in advance
I personally think that nesting tableview is a bad UX experience. Better you'll find a different approach for your users.
Saying that they also lead to different problems, for instance who scroll first etc.
In your case the issue is due to the fact that UITableViewAutomaticDimension simply send to the cell content view -systemLayoutSizeFittingSize(or similar) with UILayoutFittingCompressedSize, that for a scroll view means 0;0 basically your table view is not counted while calculating the cell height.
In my opinion now you have 2 options:
make your calculus manually and cache the result for a faster
scrolling
create a subclass of a UITableView that when asked for its intrinsicContentSize returns a custom size
Really hope this helps.

TableViewCell with multiple columns

I have an application in which I want to have a tableView with custom tableViewCell that has five columns.
I want them to be like 20%, 30%, 15%, 20% and 15% of the whole cell's width, because I want my application to launch on iPhone and iPad.
What is the best way to do this?
Now I have created a tableViewCell prototype with 5 labels. I also added constraints to them but the width constraint is just a constant. Also when I added width constraints to labels, some collisions appeared there and I don't know how to fix them.
Here is a screenshot.
You can create table view cell with collection view. By that, you can get different part in cell as well as you can change each column width programmatically based on your needs.
Thanks
A table view has only one column and allows vertical scrolling only. link
If you want to use a few columns, you can use UICollectionViewController
I also added constraints to them but the width constraint is just a constant. Also when I added width constraints to labels, some collisions appeared there and I don't know how to fix them
To fix it change width constraints to be a multiplier of superview width.

Resources