A UITableViewCell can have an accessory view (or one of the built in accessory types) associated with it, which is displayed down the right-hand edge of the cell. That’s been the case since the iOS SDK first appeared. Yawn. So what am I going to talk about?
I find it a little curious that in the world of storyboards, there’s still no great solution for hooking up custom accessory views. There’s no neat way for me to drag a view into my table cell such that the editor cleanly recognises it as being an accessory.
I could create the accessory view entirely in code and assign it at run-time. But that’s heading strongly away from my desire to see things graphically at design-time.
Alright, so I could lay out my custom accessory view on its own, and hook that up at run-time. This could be in a dedicated xib/nib file, or as a tiny freeform scene in the storyboard.
Still none of those options feel particularly pleasant; they all require code to be written to make the hookup. What goads me a bit is that .accessoryView is exposed as an IBOutlet. I figure this is of the most benefit when designing a table cell in its own nib; you still have to lay out the cell and its accessory separately, sure, but can they be seen next to each other, and hooked up in IB.
You can actually do much the same in a storyboard provided there’s only ever going to be a single instance of your cell in the table in question. Extra objects can be dragged in to a scene, and appear in that black bar underneath the view. So you can drag a custom view into that bar, configure it, and then hook up the cell’s accessoryView outlet to it. This is still pretty crummy though, as you can only actually see the view at runtime!
But then it struck me — you can perform the same trick within the cell itself! Lay out your custom view as part of the cell’s regular contentView, and hook up the accessoryView outlet to that. At run-time the cell will move your accessory to the correct spot in the view hierarchy. Just don’t forget to use the full width of the contentView for any of your other custom views!
One caveat: this doesn’t quite work if you want to hook up an editingAccessoryView instead (or indeed, as well). The accessory will be laid out correctly, but only once editing has commenced. Until that time it will still appear as part of the regular cell content. I find a little nudge is required:
Clearly I’m not the only one this bugs. My radar (16344131) has been closed as a dupe of 9478187.
I was hoping to find a better writeup of the options than my ramblings above, but no luck so far. Know of one? Please let me know.
After all that, my hand-wringing over accessory views may be for nought. The standard system accessories (e.g. disclosure indicator, or detail button) lay out with a right-hand margin of 15pt. If you assign a custom accessory view, it gets the same treatment.
But what if your custom accessory is a button? In which case that 15pt margin is an annoyance. I want my button to extend all the way up to the far right-hand edge of the cell so it has the maximum tappable area.
You can achieve this by overriding -layoutSubviews to reposition the accessory view. But at that point, the cell is supposed to have taken ownership of the view’s layout, and bodging it afterwards feels like asking for trouble.
Instead I think it’s a safer bet to lay out the view directly as part of your cell’s contentView and dispense with the notion of an accessory view entirely. It’s not too much trouble from there to move the view offscreen during editing if needed.