4

I've constructed an UICollectionView in a storyboard and implemented all of its required data source and delegate methods in the view controller. In the storyboard, I checked the Section Header property on the collection view and set the header view's class to a subclass of UICollectionResusableView (in the storyboard).

From here, I dragged in two UI elements onto the header view via the storyboard--a label and a segmented control:

enter image description here

When the program is executed, the label appears in the header view of the collection view (with no actual code required), but the segmented control does not. However, when a segmented control is dragged onto a typical UIView, it displays and is manipulatable with no code required. Even when instantiated through code in an IBOutlet, the segmented control does not appear.

Why is the segmented control not visible on the collection view's header while it is in a typical UIView, and why does the label display without issue?

UPDATE

Here is the init method for the custom header view, in which I attempted adding the segmented control programmatically (as opposed to in the storyboard):

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        _segmentedControl = [[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObjects:@"One", @"Two", nil]];
        [_segmentedControl setFrame:CGRectMake(0, 0, 100, 50)];
        [_segmentedControl addTarget:self action:@selector(segmentedControlChanged:) forControlEvents:UIControlEventValueChanged];
        [self addSubview:_segmentedControl];
    }
    return self;
}

As requested, here is the -[UICollectionReusableView viewForSupplementaryElementOfKind:] method in the main view controller:

- (UICollectionReusableView *)collectionView:(UICollectionView *)cv viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath {
    GalleryHeader *headerView = [cv dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"HeaderView" forIndexPath:indexPath];
    return headerView;
}
The Kraken
  • 3,158
  • 5
  • 30
  • 67

1 Answers1

4

I'm not able to reproduce your storyboard problem, it works just fine for me when i add the segmented control by dragging it directly in the storyboard (with no code required). As for your alternative way of adding it programmatically, the problem here is that when a view is initialized from the storyboard (as it is in this case), the initWithCoder initializer method is used (not the initWithFrame initializer method). Hence, if you override that method, inserting the code in there, it should work:

-(id)initWithCoder:(NSCoder *)aDecoder
{
    self = [super initWithCoder:aDecoder];
    if(self){
        _segmentedControl = [[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObjects:@"One", @"Two", nil]];
        _segmentedControl.bounds = CGRectMake(0, 0, 100, 50);
        [_segmentedControl addTarget:self action:@selector(segmentedControlChanged:) forControlEvents:UIControlEventValueChanged];
        [self addSubview:_segmentedControl];
    }
    return self;
}

P.S. It doesnt affect this specific case, but you should just do:

GalleryHeader *headerView = [cv dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:@"HeaderView" forIndexPath:indexPath];

instead of:

GalleryHeader *headerView = [cv dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"HeaderView" forIndexPath:indexPath];

As it is the collection view that will ask for the right kind of view, you should worry about specifying it!

EDIT: The steps i followed to create the header from storyboard are:

  • Select the collection view and tick the box labelled Section Header

  • Select the newly created header and select the right class in the identity inspector

enter image description here

  • Give the header section a unique identifier

enter image description here

  • Drag the UI elements in the header in the storyboard (i also changed its background color)

enter image description here

  • Finally implement the collectionView:viewForSupplementaryElementOfKind:atIndexPath: method in your collection view's data source class
 -(UICollectionReusableView *)collectionView:(UICollectionView *)collectionView
          viewForSupplementaryElementOfKind:(NSString *)kind 
                                atIndexPath:(NSIndexPath *)indexPath
 {
     return [self.collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"collectionViewHeader" forIndexPath:indexPath];
 }

Let me know if you can spot any difference between what you did and what I did!

micantox
  • 5,446
  • 2
  • 23
  • 27
  • Thanks for the response. I understand the `initWithFrame:` issue, and ovverode the `initWithCoder:` method instead, but to no avail. You mentioned that you weren't able to reproduce the storyboard problem. Perhaps you could send me the test project you made so I could compare the two side by side. – The Kraken Jun 18 '13 at 14:23
  • Im afraid it wouldn't be that simple to share the whole project, as i have some work stuff in it that i cannot share! Anyway hold on a second, how do you define _segmentedControl? Is it an outlet? – micantox Jun 18 '13 at 14:32
  • It's a simple property in the header file: `@property (nonatomic, strong) UISegmentedControl *segmentedControl;`, so no, it's not an outlet. – The Kraken Jun 18 '13 at 14:32
  • Would it be possible for you to share your project? – micantox Jun 18 '13 at 14:33
  • Sorry, confidential stuff on my end, too. – The Kraken Jun 18 '13 at 14:33
  • 1
    Ok, i'll edit my question and go step-by-step through what i did, maybe you can spot a difference from you did – micantox Jun 18 '13 at 14:34
  • Thanks for the edit; I really appreciate your time. I'm now getting an error: `'NSInternalInconsistencyException', reason: 'could not dequeue a view of kind: UICollectionElementKindSectionHeader with identifier facade - must register a nib or a class for the identifier or connect a prototype cell in a storyboard'` – The Kraken Jun 18 '13 at 14:59
  • Don't I need to actually instantiate `GalleryView` in the `-viewForSupplementaryElementOfKind:` method? – The Kraken Jun 18 '13 at 15:00
  • no, just change the identifier (which i just put as facade) to the one you actually put in your storyboard! In my example I should have put it as collectionViewHeader (i now edited my answer again!). You dont need to actually instantiate it, as the dequeue method does that for you! – micantox Jun 18 '13 at 15:07
  • Once again, the label displays, but the segmented control does not. – The Kraken Jun 18 '13 at 15:25
  • If I could reproduce the problem I might be able to help, but it just shows for me! Try to put the following code in your initWithFramer method and let me know what the output is: `self = [super initWithCoder:aDecoder]; for( UIView *view in self.subviews ) NSLog(@"%@", [view class]); return self;` – micantox Jun 18 '13 at 15:30
  • Sure enough, it does indicate `UISegmentedControl` as a subview. Perhaps there is just a display issue, then? – The Kraken Jun 18 '13 at 15:34
  • My guess is that you're using autolayout and some dodgy constraint is being the cause of all this! – micantox Jun 18 '13 at 15:36
  • just try disabling autolayout to confirm it – micantox Jun 18 '13 at 15:37
  • Autolayout disabled, no effect. But the control is definitely being added as a subview. – The Kraken Jun 18 '13 at 15:39
  • Gosh, this is getting quite frustrating. I wish i could just put my hands on that project! – micantox Jun 18 '13 at 15:41
  • I think I may have spotted the problem. There is a "View as" pulldown menu that allows me to view the project from an iOS 7 or iOS 6 point of view. When I clicked on iOS 7, the segmented control went away. That looks to be the problem. Give me just a moment to confirm. – The Kraken Jun 18 '13 at 15:42
  • Yup, that was clearly the source of the problem - looks like an iOS 7 gimik. Thanks very much for all your help and for leading me to the right answer. 50 points to you. – The Kraken Jun 18 '13 at 15:49
  • 1
    Thanks to you, it was quite a boring afternoon before :) – micantox Jun 18 '13 at 16:01