Table of Contents
Quick links: Project Page - GitHub - Pod
Eventually, while developing in iOS, you're going to find yourself looking for a control allowing the user to pick an option from a drop-down, selectable list of items: any UI has something like that: drop down lists, combo boxes, expand & collapse views or anything that could resemble the behaviour of an HTML <select> element.
Problem is, iOS doesn't feature anything like that. Except for the UIPickerView control, which often isn't what we really need because of its excessive height and its heavy-impact look, which isn't always as pretty as Apple designers thought it would be, at least in real-case scenarios. Conversely, we often need it to be simpler, taking less space and/or decently blending with other TextField elements.
With that thought in mind I pulled out DownPicker, an iOS control who can mimic the behaviour of a DropDownList/ComboBox using default iOS UI elements only: an UITextField to prompt the user to tap (and then show the selected item) and an UIPickerView to handle the selecting.
Custom Control or Control Wrapper
You can use it as a full-featured custom control (UIDownPicker) or as a control wrapper to "upgrade" any existing UITextField. The advantage in doing so is that you will be able to design, positioning and skin the UITextField like you always do, programmatically or inside a Storyboard UI, depending on how you are used to work.
How it looks like
Regardless of how you'll use it - custom control or control wrapper - in the end it will look just like that:
The control is lightweight and very simple to use: it only needs an array of data.
Installation
Starting Aug, 2015 you can install DownPicker using CocoaPods by following the instructions provided in this post.
If you'd like to perform a manual installation, download the latest version from this link, then unzip & drag-drop the /DownPicker/ folder inside your iOS project. You can do that directly within XCode, just be sure you have the copy items if needed and the create groups options checked.
Installing as Custom Control
Just instantiate the included UIDownPicker class programmatically and attach it to your view like any other legacy UI control:
1 2 3 4 |
@interface YourViewController () { UIDownPicker *_dp; } @end |
1 2 3 4 5 6 |
- (void)viewDidLoad { [super viewDidLoad]; _dp = [[UIDownPicker] initWithData:yourMutableArray]; [self.view addSubview:_dp]; } |
You can then customize it using the inner DownPicker public property.
Installing as Control Wrapper (recommended)
Add (or choose) a UITextField you would like to transform to a DownPicker to your existing XCode project. You can use the Storyboard designer tool or do it programmatically; you can also set up constraints, custom placement/coords, font, colors and anything else you like. When you're done, open your controller's .h file and create a property for the DownPicker wrapper:
1 |
#import "DownPicker.h"; |
1 |
@property (strong, nonatomic) DownPicker *downPicker; |
Then switch to the .m file and add these lines to your controller's viewDidAppear method:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
// create the array of data NSMutableArray* bandArray = [[NSMutableArray alloc] init]; // add some sample data [fruitsArray addObject:@"Offsprings"]; [fruitsArray addObject:@"Radiohead"]; [fruitsArray addObject:@"Muse"]; [fruitsArray addObject:@"R.E.M."]; [fruitsArray addObject:@"The Killers"]; [fruitsArray addObject:@"Social Distortion"]; // bind yourTextField to DownPicker self.downPicker = [[DownPicker alloc] initWithTextField:self.yourTextField withData:bandArray]; |
Download, Documentation & Support
- Project page on GitHub (docs, samples, api, etc.)
- Main repository on GitHub (latest versions, forks, etc.)
- Pod page at CocoaPods
- Project page at CocoaControls
- Developer page here at Ryadel.com
- DownPicker installation guide here at Ryadel.com
- Donation & support page
If you like DownPicker you can also make a small donation using PayPal to support our work.
Happy coding!
this post is a best example of “how to ruin the MVC structure for no extra benefit”.
As a matter of fact it hardly is, considering that it doesn’t give actual implementation advices or forces the developer to a specific route in any way. Please don’t take the “hello world” samples to explain how the control works as if they are programming guidelines – they are not.
Anyway, thanks for your reply.
it shows a bad example of “how. you. must. not. ever.”, and that simple fact that such post even exits is more than enough for unexperienced developers to follow such pattern as guidance.
anyway, not at all, I can help correcting the derailed ideas anytime.
I disagree with your pov: a control is not a pattern, neither the given code samples promotes or negates any possible approach. I honestly don’t see how these non-constructive critics could help anyone, if you feel like someone could cut-paste the given sample code and “ruin the MVC structure for no extra benefit”, please elaborate it.
Thanks,
I don’t think we speak the same language here, but I can try to elaborate…
you might have spotted that the original
class works with data-source delegates on purpose, which is perfectly fits in an MVC environment. (that is the “MVC structure” part).
opposite to your “brilliant” idea, which is about nothing more but getting rid of the standard MVC behaviour and pass the complete data source from model-layer toward a class on the view-layer. (that is the “ruin” part).
top on this, your picker does not provide any other advantages, which could explain why you did such changes. (that is the “no extra benefit” part).
the only constructive-criticism I could really say is… you could change this post’s entire tone to emphasise undoubtably that this is a bad idea, and it is not recommended to use it in any MVC environment – for having the proper behaviour there is the official
class from Apple.
I hope that makes perfect sense to you now.
DownPicker is by definition a UIPickerViewDataSource / UIPickerViewDelegate / UIPickerView wrapper: you can either violate or respect the MVC design pattern depending on how and where you use it. Of course you can “pass the complete data source from model-layer toward a class on the view-layer”, which is something you can do with any iOS class, but that’s completely up to you, as you can also abstract the model data in the controller – which is the case in any decent implementation. Keeping saying it “ruins” your world isn’t gonna improve the sound of your initial statement, which I still find debateable (to say the least) but well, opinions are welcome in any case :)
As for the “no extra benefit” part, I honestly find my wrapper quite convenient to handle such minor scenarios such as enum switching and/or small scale pickers which don’t have a class-structured DataSource behind. The benefit here is mostly speed, but I also like the concept of having the job handled by a single class. Again, different opinions and behaviours which have nothing to do with enforcing MVC or not.
Take care,
you may forgot about that line, which pretty much the recommended initialiser by you, and that makes the concept completely wrong:
furthermore after few paragraphs you also emphasise that thing proudly: “(…) it only needs an array of data.”
let me explain what is in my mind, because I still don’t feel we speak the same language here and you don’t understand what you did here.
not everything we could do in an iOS project we should do, like we don’t load megabytes of images into the memory just because we could – we load those only which we need. that is the core principal here and most of the developers who starts with iOS or comes with a different background (e.g. .NET, Java, etc…) mostly pick up ideas for iOS from net by googling that; most of them do not even know about official documentation and knowhow exists about “stuff” on the Apple’s site; and the “suff” can be anything like understanding why MVC is important in an iOS environment (I would actually curious about what you could say about that if someone would ask such question from you right now, and you would not be able to google it first; we will never know that, anyway) but sometimes they don’t had a clue about a simple thing like naming conventions; briefly most of them don’t have any stable background and cannot make reasonable decision between ideas they read in such posts.
what I’m actually saying is, please, don’t show a bad example to those guys, because your post encourages them to ignore MVC and concept of delegates and you highly encourage them to convert to another way like (MVVM) to pass the entire datasource to a view – which is against the MVC concept, so the “ruin” I used is still a valid argument related to your post, it does not matter your class is a subset of a proper MVC-based object, because your suggested way of implementation already violates the core principal of MVC.
you could have used own data-source delegates for your own class, actually that would be the desirable and proper way here.
take care and educate the masses responsively!
Now you’re starting to being harsh, which is something I personally don’t like (yet I guess we’ll live with that).
Just to be clear, I understood what you’re saying just fine, and I can also agree with the underlying assumption extractable from your overweening writing style – which you don’t seem humble enough to elaborate properly – which basically is (or at least
): don’t blindly bind the model to a view (MVC) unless you’re mediating it via the controller in a reasonable way (MVVM). Or maybe you’re rejecting the MVVM approach entirely, which might be perfectly fine as long as you restrain yourself from one-line joking people who don’t.
The problem we do have here is that you’re explaining it wrong, driving your logic through a wide number of incorrect assumptions enforced upon a very intentional misunderstanding of what I wrote. There’s nothing wrong in saying that a controller-level wrapper class
: my class it’s not the view, it’s the glue, and you really failed to understood and acknowledge that.
I’m glad that you learned what MVC is and how important it is in an iOS environment, yet it doesn’t allow you to go lecture people around like that ignoring the scope of what they’re writing: you’re acting like the guy who learned how to use localized language files instead of hardcoded string literals and then rushes to correct each and every “hello world” sample by saying that all these quotes in code will eventually ruin the masses. Which, by the way, ain’t as dumb as you think they are, I’m fairly sure they will eventually ditch convenience wrapper classes like DownPicker in favor of delegate-based custom implementations as soon as they’ll need to “pick” something more complex than rather small, code-based arrays like those DownPicker mostly is made for.
Take care,
I’m not sure about what you mean when you say the conversation is getting harsh; but if you referred that you should be much more responsible when you spread your ideas because you are affecting people – you are right, that is harsh.
you are also right in I completely reject MVVM on any iOS environment and I highly recommend you to do so; that might be good for a desktop app when you can have the illusion of having unlimited resources – but definitely not on iOS.
I’m just hoping people read this conversation before they start to consider to use this entirely bad idea and pattern which the post suggests.
I have to say good luck to you, because I feel pointless this conversation, because you’d say you understand my point – but the rest of your answer proves the opposite! ?
really. no offence. take care and good luck!