9

I have 3 UIViews Header / Tabar / Container embedded un a ScrollView in a ViewController. So this is my structure :

enter image description here

In the ContainerView I load a UICollectionView (like this) :

let controller = storyboard!.instantiateViewControllerWithIdentifier("myCollectionViewController") as! myCollectionViewController
controller.delegate = self

self.addChildViewController(controller)
controller.view.backgroundColor = UIColor.brownColor()
self.containerView.addSubview(controller.view)
controller.didMoveToParentViewController(self)

Everything works perfectly, each cells of the UICollectionView are loaded,... The only problem is that, all the hidden cells (and even all the parts of cells that are hidden) are not selectable. What I mean is my function "didSelectRowAtIndexPath" doesn't work for every pixel out of the first screen. This is a scheme of my problem :

This is what I have before the scroll (on the left is a scheme, on the right is what I actually have on the screen) -> here everything works fine :

enter image description here

This is what I have after the scroll (on the left is a scheme, on the right is what I actually have on the screen) -> only the pixels that were displayed before the scroll can call "didSelectRowAtIndexPath" :

enter image description here

The problem reside in the fact self.view.frame is not refreshing well. Do you have an idea of how I should change this frame and when?

Michal
  • 15,429
  • 10
  • 73
  • 104
user3369214
  • 421
  • 1
  • 9
  • 21
  • How is really the header and tab bar gets scrolled. do you have a code for that. please add it. – hasan Aug 10 '15 at 14:46
  • @hasan83 I don't really understand your question. My code is pretty heavy, which part of the code can help you ? – user3369214 Aug 10 '15 at 15:06
  • Scrolling the collection view does not scrolls the header and tab bar. How do you scroll those allowing the collection view to get more space? Apparently, you added some code to handle that logic. Add that code and the place you trigger it. – hasan Aug 10 '15 at 15:11
  • @hasan83 No, scrolling the collection view also scrolls the header and TabBar because those 3 views are embedded in a UIScrollView. I did that in the storyboard... so in my Main View I have a ScrollView where I add those 3 views (Header + TabBar + Container (in which there is the collectionViewController)) – user3369214 Aug 10 '15 at 15:26
  • In mobile development you cant embed in to scrollers inside each other you structure is wrong. Basically, your container frame is small and those pixels is not clickable because they are out of the container bounds. You only can see them because the container view mask to bounds is set to false. Also having the uicollectionview inside a scrollview loses the reusability features on cells which will cause memory and performance issues. – hasan Aug 10 '15 at 15:45
  • How would you re-structure it ? – user3369214 Aug 10 '15 at 16:04
  • I will add an answer describe that in details – hasan Aug 10 '15 at 16:05
  • @hasan83 Ok thank you, I edited my question so you have an idea of my structure – user3369214 Aug 10 '15 at 16:06
  • Have you tried using View Debugging to see what's wrong? After you scroll the "untouchable" cells visible, activate view debugging and see what's going on. My guess is either `Content` or `ContainerView` isn't resizing properly and is clipping those cells. Another way to test this is to set `clipsToBounds` to `YES` on `Content` and `ContainerView` separately and see if the cells get clipped away. That should show you what's wrong. – Jack Aug 13 '15 at 15:48

3 Answers3

2

You have to define the scroll view content size

Create an outlet to your scrollview

@IBOutlet weak var scrollview : UIScrollView!

Make its height equal the sum of the heights of the header, the tabBar and the container:

self.scrollView.contentSize = CGSizeMake(self.view.frame.width, header.frame.height + tabBar.frame.height + container.frame.height)
ielyamani
  • 17,807
  • 10
  • 55
  • 90
  • I already did this and this is some printline I have when the collectionView is loaded : - self.view.frame = (0.0, 64.0, 320.0, 416.0) - self.view.bounds = (0.0, 0.0, 320.0, 416.0) - self.tabBar.frame = (0.0, 275.0, 320.0, 50.0) - self.tabBar.bounds = (0.0, 0.0, 320.0, 50.0) - self.containerView.frame = (0.0, 325.0, 320.0, 1763.0) - self.containerView.bounds = (0.0, 0.0, 320.0, 1763.0) - self.scrollView.frame (0.0, -20.0, 320.0, 436.0) - self.scrollView.bounds (0.0, 0.0, 320.0, 436.0) - self.scrollView.contentSize (320.0, 2078.0) – user3369214 Aug 10 '15 at 17:50
  • There is no need to print the bounds. The `y` coordinate and the height are not correct in `self.view.frame`, they should be `(0.0, 0.0, 320.0, 568)` if you are simulating te app on an iphone 5/5s (have a look [here](http://www.paintcodeapp.com/news/ultimate-guide-to-iphone-resolutions)). You haven't printed the header frame. and the scrollView shouldn't be at `-20`, its coordinates should be `(0,0,320,568)` – ielyamani Aug 10 '15 at 18:02
  • Well that's true, I will change this but how this will resolve my problem ? – user3369214 Aug 10 '15 at 18:20
  • can you post the code where you create the collectionview cells? – ielyamani Aug 10 '15 at 18:50
1

Problem Definition:

All the time we face a situation were our UIViewController, in addition to the scroller view, displays headers and tab bars. The problem is that those additional views reduces the area associated to our scroller (in this case UICollectionView). In small screen devices our scroller will display a small number of items at a time.

Proposed Solution:

Let those additional views scrolls along with the scroller items.

How to Apply it?!

The most convenient solution to achieve that. Appears in the Scroller View itself. The UICollectionView for example, provides Supplementary Elements (Headers and Footers) which scrolls with the collection view items. Move your header and tabbar to the header area of the UICollectionView. then, implement the viewForSupplementaryElementOfKind in your view controller:

- (nonnull UICollectionReusableView *)collectionView:(nonnull UICollectionView *)collectionView viewForSupplementaryElementOfKind:(nonnull NSString *)kind atIndexPath:(nonnull NSIndexPath *)indexPath
{
    UICollectionReusableView *reusableview = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"Header1" forIndexPath:indexPath];

    return reusableview;
}

Interface Builder: The header area for the UICollectionView already exists. But, you need to set the height for it via the interface builder in-order to appear in design time. Do not forget to set the Collection Reusable View Identifier for the header.

enter image description here

Note: This also requires you some extra work in order to set the gestures on your header and TabBar.

Update:

Consider to remove the header and tabbar container and re-add it as a subview in it's proper place at runtime. when the UICollectionView tab get clicked pass it to the header reusable view in the viewForSupplementaryElementOfKind method. when a tab of labels get clicked add it on top of the labels container view. and when it's a tableview pass it to the UITableView header in the headerForRow method.

hasan
  • 23,815
  • 10
  • 63
  • 101
  • It's a great answer but I don't want to have Supplementary Elements (I already tried this at first but it wasn't working the way I wanted). My only solution is to embed my CollectionViewController in a UIView (called Container) inside my main ViewController. This way, I can switch with embedding different type of object in my container such as TableViewController, CollectionViewController, UILabels, ... – user3369214 Aug 12 '15 at 10:34
  • Aha, but for sure its wrong to have nested scrollers. Why dont't you consider to move you tabbar and header from view to another on tabbar button click. In other words when the collection view should appear remove the header from its superview and add it as a supplementary header. And when labels gets displayed add it as regular view and when a tableview appears add it as header view. And so on. I feel this the most appropriate un-buggy solution. – hasan Aug 12 '15 at 11:24
  • 1
    Yes @hasan83, I recoded my views using the supplementary elements and it finally worked. Thank you for your advices ! – user3369214 Aug 17 '15 at 13:37
  • 1
    There you go ;) Thank you again ! – user3369214 Aug 19 '15 at 08:39
0

This seems like the continuation of another problem you have mentioned in another question.

Looking at the storyboard hierarchy, i suspect the problem is, you are not changing the height of your tab bar view when you are changing scroll view content size and the collection view height. Collection view is still visible, probably because your container tab bar view does not clip contents (clipToBounds=false). But since the view itself does not extend that far below, touches are not recognised by the view and it's subviews.

Make sure you main view, scroll view's content view (content size), tab bar view AND collection view are all resized correctly. Since you have decided not to go with standard view hierarchy (supplementary view or header view), you have to handle the overhead of managing the view bounds yourself.

Community
  • 1
  • 1
Swapnil Luktuke
  • 10,385
  • 2
  • 35
  • 58