When layout is complete for custom UITableViewCell?

autolayout, cocoa-touch, ios, objective-c, uitableview

Solution

You seem to be set on a bespoke implementation, so here is what might work.

Calling your `-setPage:animated:` method prior to the table view setting up its subviews, giving the cell a chance to do the same, or auto layout kicking in won't work unless you maintain some state in the cell (probably just the page number) and react to one or more of the following opportunities:

Waiting until the `-viewDidLayoutSubviews` method of your UITableViewController fires and then call `-cellForRowAtIndexPath:` to get the cell. The cell should then have a valid frame.

Override `-didMoveToSuperview` in your custom UITableViewCell. By the time this is called the frame should also be valid.

After either of these points you could inspect your custom cell's state (which should contain the page number that is to be displayed) and scroll to the appropriate point. It would probably make sense to refactor your method to set the state (an integer property on the cell) and have a separate private method that `-setPage:animated:` and one of the two overrides above could call to calculate the offset and do the scrolling.

Suggested alternative:

You could pull this off by embedding a UICollectionView in the cell's `contentView`. Your UIViewController that is currently implementing UITableViewDataSource could also implement UICollectionViewDataSource and provide the collection view with its cells.

Assuming that your UITableView cells are the width and height of the screen you could configure the embedded collection view to basically paginate horizontally (since UICollectionView is a subclass of UIScrollView).

When setting up the collection view use UICollectionViewFlowLayout as the layout object and configure it up like so:

// Ensure the collection view scrolls horizontally.
let flowLayout = UICollectionViewFlowLayout();
flowLayout.scrollDirection = .Horizontal;

let collectionView = UICollectionView(frame:tableCellFrame, layout:flowLayout);

// These are actually UIScrollView properties.
collectionView.pagingEnabled = true;
collectionView.bounces = false;

You then place each page of content in a custom UICollectionViewCell and the collection view will paginate them for you. This has the added bonus of providing you with a paginated scrolling API for free.

Problem

I have a custom table view cell defined in the storyboard file. This cell contains scroll view with few pages of content and a page indicator. Scroll views, content view and cell itself all defined using auto-layout. Page1/2/3 views are bind to have same width as scroll view, and container bind to have 3 times width as scroll view. This way I unsure that content is exactly sized to show three pages of information regardless of screen size. I have a code in the custom cell class to update page indicator when scroll view did scroll - this works fine. I also exposed the method in the cell class to specify page from outside, and in this setter I'm doing something like that: ``` - (void)setPage:(NSInteger)page animated:(BOOL)animated { CGFloat pageWidth = self.scrollView.frame.size.width; self.pageControl.currentPage = page; [self.scrollView setContentOffset:CGPointMake(page*pageWidth, 0) animated:animated]; } ``` The problem I'm facing is quite often scroll view frame and content size is not defined properly when I'm calling this setter, so the page indicator would be set, but scroll view doesn't change content offset. Where can I catch a moment that my cell auto-layout is complete and I can guarantee that setContentOffset will work? I have try to call `setPage` from `cellForIndexPath` - that obviously doesn't work, then I tried to call it from `willDisplayCell` - same story - cell itself is already laid out properly, but scroll view still has 600px (from storyboard) and it fails.

Original source