UICollectionView’s backgroundView property is horribly broken

I want to love UICollectionView, I really do. But it continues to give me reasons to complain about it instead. I was working on some iOS 7-ish UI in our yet-to-be-announced project and trying to use the backgroundView property of a few collection views. To make the app feel more “alive”, I started occasionally updating this backgroundView to better reflect the current state of the app. Except, it just wasn’t working!

I went round and round for quite some time trying to figure out where my code was broken; then ultimately concluded that setting the backgroundView property simply would not be reflected once it had been set a single time. If I did something like the following, the result would always be a collection view with a red background, not the blue background I was expecting.

UIView *redView = [UIView new];
redView.backgroundColor = [UIColor redColor];
collectionView.backgroundView = redView;

UIView *blueView = [UIView new];
blueView.backgroundColor = [UIColor blueColor];
collectionView.backgroundView = blueView;

I had accepted that backgroundView was broken, and planned to just put my own view behind the collection view (one that did what I asked it to), but I couldn’t get past wondering how this property could possibly be so broken. In my initial Googling, I had stumbled on an old GitHub issue for PSTCollectionView; the issue suggested that the backgroundView property had always acted odd when adding the provided view to the view hierarchy. How could this property just not work!?

The Big Reveal

I wish could say I did this part on purpose. I had Reveal open from some previous troubleshooting (Have you bought Reveal yet? If you haven’t, you should — it’s insanely useful), and lo and behold, right there in the exploded view I could see all the background views I had been adding. They were all just in the wrong place! The UICollectionView had been adding my provided backgroundView to the view hierarchy, but was never removing the old one.

Given our code above, the results in Reveal might look something like this:
Screen-Shot-2013-11-15-at-4.44.52-PM

Hilariously, if not completely expected, the collection view will stack as many backgroundViews, in reverse order, as you are willing to give it.
Screen-Shot-2013-11-15-at-4.47.28-PM

The Solution

Frankly, I think the best solution is to just ignore the backgroundView property all together. Instead, make the collection view’s background clear, and implement your own backgroundView; just throw a view behind the collection view.

It turns out, not unsurprisingly, the backgroundView property is workable as long as you manually remove it from it’s superview before setting it to a new value. Modifying our code from above, the following works as expected:

UIView *redView = [UIView new];
redView.backgroundColor = [UIColor redColor];
collectionView.backgroundView = redView;

UIView *blueView = [UIView new];
blueView.backgroundColor = [UIColor blueColor];
[collectionView.backgroundView removeFromSuperview];
collectionView.backgroundView = blueView;

Screen-Shot-2013-11-15-at-4.53.24-PM-1

But wait, there’s more

Just in case you aren’t yet convinced that backgroundView meets the criteria for horribly broken, I have one more ridiculous example to provide. In preparation for this blog post and a bug report for Apple, I put together a sample project. It simply iterates over a short array of colors and creates colored views to assign as a backgroundView. Initially, I added this code to my viewDidLoad method, and my collection view was oddly — empty.

Of course, once again Reveal made this easy to investigate. And while I still have no hypothesis for how exactly the collection view managed to put itself in this state, you can see in the screenshot below that the cells have somehow been positioned behind my initial backgroundView.

- (void)viewDidLoad
{
    [super viewDidLoad];
	
	NSArray *colors = @[[UIColor redColor],
						[UIColor blueColor],
						[UIColor greenColor],
						[UIColor orangeColor]];
	
	for (UIColor *color in colors) {
		UIView *view = [[UIView alloc] init];
		view.backgroundColor = color;
		self.collectionView.backgroundView = view;
	}
}

Screen-Shot-2013-11-15-at-5.11.26-PM

Jerry Jones

About Jerry Jones

Co-Founder of Spaceman Labs, Inc. Formerly of Mellmo, Inc. iOS Developer since 2007. You can find me on LinkedIn, Twitter, and doing backflips on jet skis.
This entry was posted in Uncategorized. Bookmark the permalink.

4 Responses to UICollectionView’s backgroundView property is horribly broken

  1. Rawnsley says:

    Thanks for confirming what I suspected, but couldn’t bring myself to believe. Filed under “why do they hate me?”

  2. Brock Boland says:

    Thanks for posting this! I was looking for info on background images yesterday, and sure enough, ran into this bug today. I’m glad I saw this, or I would have been downright bumfuzzled.

  3. msmollin says:

    For those people finding this now, this is now fixed in iOS 8, which makes it annoying if you wanna support 7 and 8 at the same time. However the solution to remove it from superView manually still works.

  4. Nicolás Miari says:

    Interesting. But instead of setting the collection view to transparent and laying your background view behind it… Why can’t you just keep a reference to the initial view you set as its background, and then change the background color of that view? That way, your view hierarchy outside the collection view is leaner.

Leave a Reply

Your email address will not be published. Required fields are marked *