Zack Brown
Zack Brown

Reputation: 6028

Building a custom UIPickerView

I am trying to build a custom UIPickerView replacement class mainly for learning purposes but with a view to implementing this within an application I am developing. I have put a lot of time and effort into the UI of my application and now the default UIPickerView just doesn't fit right.

I saw this Dribble mock up of a really slick looking date/time picker but realise that theres not a chance in hell that UIPickerView can be customised this heavily without some major hacking.

After a whole lot of reading and investigation, I have found that UIPickerView uses UITableViews for it's components rather than a plain UIScrollView as I had first assumed. This is confusing for two reasons:

Customising UITableViewCells is a major pain in the derriere. It's not that it's hard work, just laborious and rarely yields the required result. Somehow UIPickerView manages to pull this off though with very little overhead. I would assume that each row in a component just uses UITableViewCellStyleDefault with a custom view for it's contentView but you know what they say about assumptions.

The second thing that is throwing me off is that UIPickerView conforms to the UITableViewDataSource protocol, but not the UITableViewDelegate protocol. This seems a little odd as the delegate is responsible for providing the correct height via – tableView:heightForRowAtIndexPath: UIPickerView however does allow you to set the size of a component via – pickerView:rowHeightForComponent:

In line with this, it also seems a strange choice to utilise a table view as natively these do not "snap" to a specified row the way a scroll view would with pagingEnabled.

Can anyone offer up an explanation of why the default UIPickerView doesn't conform to the aforementioned delegate? Would it be easier for me to implement my custom picker with a UIScrollView instead or should the UITableView provide the functionality required?

Upvotes: 1

Views: 1804

Answers (3)

rghome
rghome

Reputation: 8819

I managed to implement an "alternative" UIPicker by extending UICollectionView.

Although UICollectionView is usually used for cases where you have multiple items in a section, you can just have one item and it works fine. If you enable paging you get similar behaviour to a UIPicker, but it has a "stickier" scroll that only lets you scroll one item at a time, which might be better if that is what you want. Furthermore, you can scroll vertically or horizontally. You could even have a 2D picker with some extra code.

Upvotes: 0

Mathieu Amiot
Mathieu Amiot

Reputation: 1214

Custom UIPickerView are done by mimicking it's behavior using an UIViewController subclass containing as many UITableView you need for fields.

Eg: if you want a time picker, use 2 tableviews

You should style them in a xib using images and such.

What's -kinda- hard about reproducing the behavior is the part where UIPickerView "snaps" to the closest cell, and especially getting it right.

Also, cells in a UIPickerView are simple, just no borders/delimiters between cells, text label is centered, and voilà. What you see are just images overlaid in front of the UITableViews.

As to why it doesn't fully conform to the UITableViewDelegate, it's because in fact, it's a lightweight UITableView that snaps automatically that is used internally in UIPickerView. Thus, it lacks some delegates that are not specially useful for this.

But I guess we all agree on one thing: Indeed, building custom UIPickerView is a big pain and should be easier.

Take a look at this component, looks quite nice, though I haven't tested it myself. computerlogicx/AFPickerView

Upvotes: 0

Vladimir
Vladimir

Reputation: 170819

  1. UIPickerView actually conforms to UITableViewDelegate protocol but just does not expose that in public headers. You can check that yourself using class_copyProtocolList function.

  2. Using UITableView internally makes it much easier to implement pickers with large amount of rows as UITableView provides great support for reusing cells, otherwise Apple would need to reimplement that logic once again for picker - that would not make much sense (sorry I don't see any big problems in customizing UITableViewCell for this case, so it is hard to comment on that)

  3. As UITableView is UIScrollView subclass you can make it "snap" to a specific position, check scrollViewWillEndDragging:withVelocity:targetContentOffset: method in UIScrollViewDelegate protocol that can be used for exactly that purpose.

Upvotes: 3

Related Questions