How do I get the size for a UICollectionView cell when layoutSubviews hasn't been called - ios

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()

Related

One of my UICollectionViews is not scrolling or responding to touch events inside my UIScrollView container [Puzzling]

I have an unusual and challenging problem. I have researched deeply on StackOverflow and have been unable to find any solutions. Please do not ask about my design style- it must be this way.
I have a UIPageViewController that contains a UIScrollView which contains 4 UICollectionViews. Each of these collection views should be horizontally scrollable but not vertically scrollable. The scroll view is necessary because the screen is not large enough to display all 4 collection views. Upon loading the screen, the 4th collection view is not immediately visible. After scrolling down, the 4th collection view then becomes visible.
The problem I am having is the 4th collection view does not respond to touches. Specifically, it does not respond to taps or attempts to scroll. The other 3 work perfectly fine. What makes this puzzling and odd is that the 4th one is exactly the same as the other 3, the delegate and data source are set properly and user interaction is enabled. The only real difference between the problematic collection view and the others is that it is not immediately visible when the screen loads.
When I attempt to scroll it behaves as if I am trying to change the page, so the UIPageView changes the page. So the CollectionView isn't registering any touches at all. I have a hunch that it either has to do with the GestureRecognizer from the PageView or something to do with how it isn't visible on the screen upon the initial load.
Any thoughts?
Not 100% sure without seeing the initialization of code or storyboard, but the best thing is that maybe there is a view overlapping. You can run your program and click on the 2 overlapping rectangles. This is the Debug View Hierarchy. It shows you your current frame on your phone and you can see the view laid out in hierarchal status.
Solved my own problem thanks to impression7vx's mention of the Debug View Hierarchy. Had no clue this existed but it let me discover the flaw. I am just writing this to help people who stumble upon this in the future.
I had a content view inside the ScrollView that had a problematic constraint. I set it to have "Equal Heights" with the ScrollView but upon loading the screen the height was static. Only half of the scroll view showed and that half would be registered as the height for the UIView. Since it was static the view would not become larger when I'd scroll, and the 4th collection view would not be inside that container view anymore. For some reason, since the collection view wasn't in the container view it wouldn't register touches.
Solved by manually making the height the same value of the scroll view! This allowed the content view to contain all of the collection views which made them behave normally again.
Just take NSLayoutConstraint of height of the UIView inside the UIScrollView
#IBOutlet weak var scrollContentViewHeight: NSLayoutConstraint!
Set height of this scrollContentViewHeight equal to height of dynamic size of the UIScrollView
if scrollableView.contentSize.height = 840.0
then
scrollContentViewHeight.constant = 840.0
set it on viewDidLayoutSubviews
override func viewDidLayoutSubviews() {
scrollableView.contentSize.height = 840.0
scrollContentViewHeight.constant = 840.0
}

Multipage UICollectionView with View

I am trying to create a collection view layout similar to the one used by Twitter and Product Hunt. I want to have a horizontal collection view to tab between data while also maintaining vertical scrolling in the tab I am in. I do not want to just change the datasource that is loaded into the UICollectionView. I have tried several different layouts but none of them have been successful.
Right now, I have a UIViewController with a UICollectionView & UIImageView object inside of it. The UIImageView's size is (3/8) of the UIViewController's frame and begins at (0,0). The UICollectionView's frame is equal to the UIViewController's frame but the cv is offset to be below UIImageView & its size is equal to the size of the UIViewController's view. The (1) cell inside the UICollectionView has a UICollectionView inside of it -- this can be configured with the data you want (multiple cells). This layout works fine for a single datasource.
However, when you want to have multiple datasources accessed by scrolling horizontally the layout breaks down. You have to change the flow layout of the outermost UICollectionView to horizontal. When you do this, you get a layout error because the size of the collection view is larger than than the view and you cannot scroll vertically.
If you reference the image I provided, I think you can infer what the desired layout should behave like. You should be able to access the other datasource by horizontal scrolling but also be able to scroll the current collection view full screen and not have it fixed to the bottom of the UIImageView. I tried adding logic to the scrollview delegate methods but that didn't work either. Thanks]2

Best time in View lifecycle to determine the on-screen size of a UIScrollView

I have a .xib containing a view which itself containing top and bottom accessory views (navigation, a page control) and a UIScrollView. Its height varies depending on whether I'm running on an iPhone 4 or 5 (3.5" or 4"). At runtime I move the containing view offscreen, populate the scrollview with UIButtons to build a scrollable launchpad, and scroll this on to the screen from the bottom. Tapping a button shows another view.
On a smaller screen I'd like to show only three buttons in the scrollview, on the larger one I show four. So I need to know the height that the scrollview will be when it appears, before it actually appears. I'd hoped to have this information available at some point in the view lifecycle (viewWillAppear etc.) but the only place this seems to be correct is in viewDidAppear. At this point the view is already on screen and creating the buttons then means they appear suddenly, and are not scrolled nicely onscreen.
The top-level view in the .xib is set to Retina 4 FullScreen.
I'm happy to concede that viewWillAppear is the correct place to create the buttons and my navigation controller is perhaps instantiating the view incorrectly, but my iOS-fu isn't strong enough to say for certain.
My solution has been to detect screen size and hardwire the button height. Is there a better (more elegant, future-proof and canonical) way to do this?
Don't worry, you are in the right direction:
viewWillAppear is the correct method in a view's lifecycle, where the frames of that view and its subviews are completely calculated and nothing has been drawn yet. Here you can make corrections to the standard behavior of your view.
When viewDidAppear gets called, you get the same information about positions and sizes of view elements as in viewWillAppear. But at this time, the animations and the view itself already have been drawn.
That is, why you'll want to use viewWillApear.

iOS UITableViewCell with scrollView with dynamic content

I am trying to create a table view, in which the table view cells contain a scroll view. The scroll view can contain one or two pages of one image view each. Note that the scroll view will only scroll horizontally, so it will not interfere with the Table View's scroll view that will scroll vertically. Depending on the content, I want the scroll view to be updated with these image views, and set the scroll view content size according to responses I receive from a server, instructing the application what images to display.
In order to do that, I initially thought of creating a custom UITableViewCell subclass, and do all my initialisation of the views inside that.
However, I am just thinking about performance and memory. I know that iOS automatically deallocates already seen views and cells, when it needs to, and that it reuses the old cells when it tries to display something new (by using a reuse identifier). However, each cell will contain a scroll view with content size and subviews that will change in each cell. I want to use a reuse identifier to ensure maximum performance.
Can anyone point me in a way in which I can set up the reuse of a cell like this, and change the contents of each scroll view successfully?
Thanks.
you can make the reuseIdentifier dynamic
e.g. "cell_with_1","cell_with_2","cell_with_x" where x is the number of images
that way equal cells can be reused when sensible (e.g. when the number of images in the view is the same): 'worst case' is no reusing and a tad overhead for trying but in general I'd deem it beneficial :)
*the allocation deallocation and the basic adding of the subviews is expensive.. changing frames or images seems reasonable to me

Getting real width of UITableViewCell's contentView before it displays

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.

Resources