I have a grouped table view with custom cells (created programmatically by subclassing, not with IB). To properly position custom cell's subviews (such as labels and text fields), I need to know the current width of the cell's contentView just before the cell displays (taking into account that real cell width in a table view can change (according to screen orientation, modal presentation style, etc.)).
if I override in custom cell class the layoutSubviews method, it works perfectly, but it can be called frequently, thus I have to reposition my subviews every time when it's called, even when there's no need to do that.
Please, recommend me more elegant solution.
The recommended way of doing this is by setting the autoresizingMask of the table cell. If you need to have more control over the layout, you can store the last used view width in a member variable, and only layout the subviews if this differs from the current view width.
Related
iOS 13 (but seems to hold true in iOS 10.3, also).
I'm having a very hard time getting the final height of a view in a complex view hierarchy before anything is drawn to the screen. I have a UIPageViewControl with a series of custom UIViewController. One of the subviews in that is a table view, and I want to adjust the cell height based on the table view's height so that I have an integral number of cells showing.
Unfortunately, the final height of the table view is not determined, it seems, until after all hooks have been exhausted. I've tried all of the following: viewDidLoad(), viewWill/DidAppear(), viewDidLayoutSubviews(), layoutSubviews() and didMoveToWindow() (on the table view and the root view). I've tried calling layoutIfNeeded() in each of the above.
In the end, well after didMoveToWindow() (which comes after viewDidAppear, annoyingly), layoutSubviews() gets called a couple more times, and it’s only in those last two calls that the view has its final height. At this point it’s not possible to set the cell height and reload the table view without it visibly changing on-screen.
There seems to be no way to accomplish this.
Am I missing something? I guess I can try UICollectionView instead.
I have a UITableView with several columns of data. The reusable cells are loaded from an xib file which has the appropriate labels and autolayout constraints. Everything works perfectly; the table columns are laid out correctly on different devices and when the devices are rotated.
The problem I am having is trying to create a table footer to show the totals of the columns in the table.
I created an xib file with the same autolayout constraints as the cell xib file and am loading it in tableView.viewForFooterInSection the same way I did for the cells. As required, I am using a subclass of UITableViewHeaderFooterView instead of UITableViewCell.
The awakeFromNib method in the UITableViewHeaderFooterView subclass sets the background color, so I can see that it is the correct size on all devices/orientation, but the labels from the footer xib file are not getting laid out to match the table cells.
The autolayout constraints from the footer xib file are not being honored. When I set a different background color in the footer xib file, the table footer shows this background color for the length of the xib's view.
I'm new to all of this technology and would greatly appreciate help in resolving this incredibly frustrating issue.
Is there a way to use autolayout for UITableViewHeaderFooterViews loaded from nibs?
You should call setNeedsUpdateConstraints() to update your view.
From apple documentation
Controls whether the view’s constraints need updating.
When a property of your custom view changes in a way that would impact constraints, you can call this method to indicate that the
constraints need to be updated at some point in the future. The system
will then call updateConstraints as part of its normal layout pass.
Updating constraints all at once just before they are needed ensures
that you don’t needlessly recalculate constraints when multiple
changes are made to your view in between layout passes.
Also, you can update view throw layoutSubviews()
Lays out subviews. The default implementation of this method does
nothing on iOS 5.1 and earlier. Otherwise, the default implementation
uses any constraints you have set to determine the size and position
of any subviews. Subclasses can override this method as needed to
perform more precise layout of their subviews. You should override
this method only if the autoresizing and constraint-based behaviors of
the subviews do not offer the behavior you want. You can use your
implementation to set the frame rectangles of your subviews directly.
You should not call this method directly. If you want to force a
layout update, call the setNeedsLayout method instead to do so prior
to the next drawing update. If you want to update the layout of your
views immediately, call the layoutIfNeeded method.
I have a table view and its every cell`s width say 1024px , so my requirement is after clicking a cell tableview's width will change logically. And my table view is bit complex.
Every cell contains a custom view which is defined in another class. Please help me..
I do not believe there is a way to modify a single cell's width without changing the width of the table view, only height using tableView:heightForRowAtIndexPath:.
Therefore, you might want to change the width of the custom view inside your cell.
First, to get the cell in question, call cellForRowAtIndexPath: on your table view wherever you need (if you want to change the width on tap, that would probably be in your tableView:didSelectRowAtIndexPath:).
To access your custom view, you may give your custom view a tag number inside of the UITableViewCell by setting the custom view's tag property when creating the cell or in the storyboard. Then, call viewWithTag: on the UITableViewCell instance to get the custom view, and modify the width of its frame property.
Another, perhaps more suitable option would be to use a custom UITableViewCell class for your table view cells. That would mean subclassing UITableViewCell and creating a property for your custom view, which would allow you to access the custom subview through the getter and then change its frame property.
If you need the width of the custom view's container to change (which is currently your cell), simply embed the custom view inside a UIView and modify the UIView's width rather than the UITableViewCell's instance in the same manner described above.
I'm trying to create a UICollectionView where the cells are varied sizes based on the contents within them and how those contents play with the constraints set on them. Basically, I need to examine the frame size but this size isn't updated on the cell until after the subviews have been laid out. Unfortunately, this isn't done until the view is attached to the window hierarchy it seems. I can't find any series of calls to trigger this without adding it to the window hierarchy, yet I don't want to add it to the hierarchy except through this UICollectionView. And, of course, the collection view wants the size of it before it requests and adds the cell.
I can't get to size without adding it to the window hierarchy (I think), and I can't get it added to the window hierarchy (i.e. the collection view) without having the size. What am I missing here?
Just call these on the cell, and it should act as though it was added to the view hierarchy:
setNeedsLayout()
layoutIfNeeded()
In iOS6, I cannot seem to get the width of the cell in cellForRowAtIndexPath for the grouped table style. Logging either the frame or the bounds for either the cell or its contentview returns 320 - even on iPad. I need to determine the cell width programmatically for any device as I need to calculate text sizes. Any advice in getting the correct cell width for a grouped tableview in cellForRowAtIndexpath would be appreciated please
The method you're using is the wrong place to calculate any kind of view-related constraints. The -tableView:cellForRowAtIndexPath: method is part of the table view's data source, not its delegate. You cannot rely on the frame or anything else here to be meaningful, it's meant as the place to configure the cell's /data/.
If you need to make calculations to view frames and such, and you're not using a custom subclass of UITableViewCell (i.e., you're just adding views to a default instance of UITableViewCell or configuring stock views), you would set up any frame-related / view specific attributes in the /delegate/ callback -tableView:willDisplayCell:forRowAtIndexPath: method. This is the place to configure any of the visible/view-related properties of your cell, and you will now have accurate layout information for the cell (its bounds will be correct, any layout/configuration of internal views will be complete, etc.).
If you have a custom subclass already, you can either do your view related property configuration in the delegate callback above, or you can do it in UIView's -layoutSubviews method, depending on your exact needs. For more information, see the documentation for -tableView:willDisplayCell:forRowAtIndexPath:.