Additional View getting inserted into UICollectionView loaded from Xib

351 Views Asked by At

I am having a weird issue with using a Xib for UICollectionViewCells. The issue is that an additional view is being created, that seems to be on top of everything, rendering my gestures and IBActions useless.

Here's my setup:

  • I have a UIViewController with a UICollectionView in it.

  • In the storyboard, the UICollectionView has a single cell, of class "MyCell", with reuse id "cell"

  • In cellForItemAtIndexPath, I only return the result of [collectionView dequeueReusableCellWithReuseIdentifier:@"cell" forIndexPath:indexPath]. I also hardcoded 30 items in numberOfItemsInSection.

That's that. Besides that, I have MyCell.h, MyCell.m and MyCell.xib.

  • The xib contains a single UIButton, whose Touch Up Inside event is set to call the buttonPressed IBAction. The view itself is set to the class MyCell and the tag is set to 123 (we'll get to why below).

  • In MyCell.m, I overrode awakeAfterUsingCoder to return [MyCell initView:self]. The definition of initView is at the bottom. But it basically loads the view from the Xib.

That's it.

When I run the app, 30 cells show up, all with their button, but when the button is pressed, nothing happens. After a lot of investigating, I found that there's an extra UIView added inside the cell, which is on top of the button, and it's covering the entire thing.

If I add the for-loop below inside awakeAfterUsingCoder, then the button works again.

    - (MyCell *)awakeAfterUsingCoder:(NSCoder *)aDecoder
    {
        MyCell *cell = [MyCell initView:self];
        for(UIView *v in cell.subviews){
            if(![v isKindOfClass:[UIButton class]]) [v removeFromSuperview];
        }
        return cell;
    }

My question is: what is that view, and why is it there??? Even though I can get everything to work by removing that view, it feels like a hack.

Thank you! And I can answer any other questions if necessary.

    + (id)initView:(UIView *)viewToInit
    {
        UIView *viewToReturn;

        if(viewToInit.tag != 123){
            //If we're in the storyboard codepath

            //Initialize from the xib.
            //If the code below is failing, we probably forgot the 666 tag :/
            viewToReturn = [[[NSBundle mainBundle] loadNibNamed:NSStringFromClass([viewToInit class])
                                                          owner:nil
                                                        options:nil] firstObject];

            //copy frame, autoresizing, and layour items.
            viewToReturn.frame = viewToInit.frame;
            viewToReturn.autoresizingMask = viewToInit.autoresizingMask;
            viewToReturn.translatesAutoresizingMaskIntoConstraints = viewToInit.translatesAutoresizingMaskIntoConstraints;

            for (NSLayoutConstraint *constraint in viewToInit.constraints){
                id firstItem = constraint.firstItem;
                if (firstItem == viewToInit){
                    firstItem = viewToReturn;
                }
                id secondItem = constraint.secondItem;
                if (secondItem == viewToInit){
                    secondItem = viewToReturn;
                }

                [viewToReturn addConstraint:[NSLayoutConstraint constraintWithItem:firstItem
                                                                         attribute:constraint.firstAttribute
                                                                         relatedBy:constraint.relation
                                                                            toItem:secondItem
                                                                         attribute:constraint.secondAttribute
                                                                        multiplier:constraint.multiplier
                                                                          constant:constraint.constant]];
            }
        }else{
            //otherwise do nothing and just return what was passed in
            viewToReturn = viewToInit;
        }

        return viewToReturn;
    }
2

There are 2 best solutions below

0
On BEST ANSWER

I've just had this problem myself, and the answer lies in the cell nib file. If you've created a nib and are using the stock UIView contained as a cell, that's where your problem is. This UIView needs to be deleted immediately and replaced with a newly-dragged-on UICollectionViewCell. This will then be your cell, and you can add views to your hearts content without further issues.

2
On

OK, so after a long time of having a nasty hack in there to work around this, I've figured it out.

The issue is that the contentView of the UICollectionViewCell is getting inserted on top of my views. It is very weird to me because this doesn't happen with UITableViewCells which also have a content view.

What I did then, was to put everything in a "container" view and then move that container view into the contentView on init, and that took care of the problem.

I still don't understand WHY this is happening. It seems to me that all my views should be added into the contentView (like the table's cells do), but at least I can now work around it.