A Replacement For ActionSheet Date Picker

ModalPickerViewController

In the earlier days of Xamarin.iOS development (up to iOS 7), one of the more useful recipes from the Xamarin Documentation was the ActionSheet Date Picker.  Adding a DatePicker as a subview of a UIActionSheet was a very convenient way to display a DatePicker to the user.  The Action Sheet would behave as it usually would, and you could modify it to slide from the bottom and only take up the bottom portion of the screen.  After the user selects the date and taps on “Done”, the ActionSheet would then slide back down.  Because of the behavior of the ActionSheet, this was a great way to provide a Modal Date Picker.  However, this recipe no longer works on iOS 8 due to “misuse” of the UIActionSheet.  I created an alternative, with full source code and sample app that replaces the ActionSheet Date Picker that is free to use.

Actionsheet Date Picker

ActionSheet Date Picker Example

An Ominous Hidden Warning

If you even ran the ActionSheet Date Picker, you may have noticed a few warnings/errors that appeared in your output window when the ActionSheet Date Picker would launch on an iOS 7 device or Simulator.  The warning looked something like this:

<Error>: CGContextSetFillColorWithColor: invalid context 0x0. This is a serious error. This application, or a library it uses, is using an invalid context and is thereby contributing to an overall degradation of system stability and reliability. This notice is a courtesy: please fix this problem. It will become a fatal error in an upcoming update.

Though this was only a warning, the app remained stable and executed as one would expect.  I myself remember seeing these errors and wondered why was I getting these messages.  What scared me the most was the last two sentences of the message.  I decided to do a little investigation and as it turns out, Apple never intended the UIActionSheet to be used in this way.  From the Apple Documentation, there is a little note that states:

UIActionSheet is not designed to be subclassed, nor should you add views to its hierarchy. If you need to present a sheet with more customization than provided by the UIActionSheet API, you can create your own and present it modally with presentViewController:animated:completion:.

So as it turns out, Apple does not want you subclassing or adding your own subviews (like an UIDatePicker) to the ActionSheet.  And starting with iOS 7, it gave warnings in your output window to fix the problem, or else.  So now, the “upcoming update” is here.  Welcome to iOS 8.  And as promised, subclassing the UIActionSheet or adding your own views to it now produces a fatal error that crashes your app.

A Possible Solution

In the Apple Documentation (shown above), the last sentence stated that you can create your own (in the form of a UIViewController) and present it modally using the PresentViewController() method.  Several months ago I was in a dilemma.  I knew that iOS 8 was going to be released sometime during the Fall of 2014.  That’s a given for sure, but at the time I didn’t know the exact date.  I could either fix this issue now, or wait down the line and, most likely, be in a panic to fix this critical issue at the last minute.  Fortunately, I decided to fix the problem then because I didn’t want to put myself into a position to rush an emergency fix for iOS 8.

So I went ahead and created the ModalPickerViewController.  This took me about a day to flush out.  I thought it was going to be straight forward and easy to code up.  For the most part it was, but creating the slide-up/slide-down transitions and supporting Portrait and Landscape modes proved to be a little challenging.  But when it was all said and done, the output was a modal Date Picker that mimicked the ActionSheet Date Picker.

How To Use The ModalPickerViewController

Using the ModalPickerViewController is pretty straight forward.  Below is a step by step process.

Step 1: Create An Instance Of ModalPickerViewController

First, you want to create an instance of ModalPickerViewController.  The constructor accepts 3 parameters: a ModalPickerType, a title for the header, and a reference to its parent view controller.

There are also several properties you want to initialize.  The HeaderBackgroundColor is the color of the view controller header.  The HeaderTextColor is the font color for the header text.  The next two properties are really important.  Set the TransitioningDelegate to a new instance of ModalPickerTransitionDelegate.  This is what defines the slide-up/slide-down transition.  Also set the ModalPresentationStyle to Custom.  This tells the View Controller that when it is presented, it will use the ModalPickerTransitionDelegate for its transition.

Step 2: Set Your Date Picker Mode

Next, you want to set the DatePicker mode.  You can set it to anything you want, but for this example, I’ll set it to Date.

Step 3: Wire Up The OnModalPickerDismissed Event Handler

This event will fire after the user selects the date and taps on “Done”.  In this event handler, you can extract the currently selected date and use it as you see fit.  In this example, I’m just taking the selected date and displaying it on a UILabel called “PickedLabel”.

Step 4: Show the ModalPickerViewController

The final step is to show the ModalPickerViewController by call PresentViewController() or PresentViewControllerAsync()

The final output should look like this:

ModalPickerViewController

ModalPickerViewController output

Where To Get The Code

You can download the source code along with a Sample App by visiting my GitHub Repo at: https://github.com/SharpMobileCode/ModalPickerViewController.  You’re free to use it and modify it if you need to.  I only ask that if you add something useful or fix a bug, that you submit a pull request and submit your changes.  I would benefit us and the rest of the community.  The sample code also includes an example of using a custom Picker View.  So you can use a custom picker if you want to show custom formatted dates, or anything else for that matter (a list of colors, people, states, cities, etc).  It’s all in the sample.

Areas For Improvement

The ModalPickerViewController also supports landscape orientation.  Though I’m not quite happy with the transition.  When you rotate the device to landscape and then back to portrait, you’ll notice that the transition is a little choppy.  I would rather have it be a little smoother. The ModalPickerTransitionDelegate class is what defines the transitions.  I really didn’t want to spend too much time perfecting this, but if you would like to give it a shot, feel free. :)

Summary

I hope you found this useful.   And as usual, feel free to send me an e-mail or leave a comment.  Also if you’d like to contribute and help improve this project feel free to submit a pull request on GitHub.


  • xhaman ik

    Perfect solution for me, I owe you my thanks

  • Hepp Heppson

    This just blows my mind! What an aaaaaaaaamazing job! Thanks for sharing! This saved me so many hours of struggle, and it also looks better than anything i can imagine cooking up myself.

  • Fernando Feijão

    Perfect solution!!! Thank you

  • Mark Reynolds

    Great solution, just what I needed!

  • Renato Todorov

    Great work mate, you should definitely create a NuGet package for it!

  • Renato Todorov

    Also, it would be great if you could merge the Unified API PR. Thanks.

    • Just upgraded the project to the Unified API. Sorry for the delay!

      • Renato Todorov

        Cool, thanks! I have used the version from the PR but that’s great!

  • Ryan Seda

    Fantastic solution and very easy to implement. Thank you for such a thorough explanation.

  • Ashley

    Anyone else have the problem where only the menu is showing up at the bottom of the screen but no actual date picker?

    My Code:

    _datePicker = new ModalPickerViewController(ModalPickerType.Date, StringConstants.SelectDate.Local(), this)

    {

    HeaderBackgroundColor = UIColor.Red,

    HeaderTextColor = UIColor.White,

    TransitioningDelegate = new ModalPickerTransitionDelegate(),

    ModalPresentationStyle = UIModalPresentationStyle.Custom

    };

    _datePicker.DatePicker.Mode = UIDatePickerMode.Date;

    _datePicker.OnModalPickerDismissed += (sender, e) => ActionSheetOnDismissed();


    new StyledStringElement (StringConstants.SelectDate.Local (),()=> PresentViewController(_datePicker, true, null))

    Any help would be appreciated!

    Ash..

    • Greg James

      Ash, I do get the same, where the picker (date or custom) does not show. This occurs only on iOS 9 (not iOS 8). I am yet to find a resolution.

      • Ash posted on the Xamarin forum here, but has not provided a sample project that re-creates the issue. I’ve got this working on a production app on iOS 9 devices. If you can post a sample app that re-creates the issue on the Xamarin Forums, I’ll take a look at it.

        http://forums.xamarin.com/discussion/comment/152395/#Comment_152395

        • Greg James

          Hi Ruben

          I have been able to replicate this using the sample application. I am now updating everything locally to the latest stable versions (was using beta channel for Xamarin and GM for iOS 9), and will retest. If it still fails I will create an issue.

          • Quick question. Did you compile the project against the iOS 9 SDK and then run it on an iOS 9 device? Or did you compile again the iOS 8.X SDK and then ran it on an iOS 9 device? I’m still compiling against the iOS 8.4 SDK and it runs fine on an iOS 9 device.

          • Greg James

            iOS 9 sdk then run on a iOS 9 device. Note that when the same app is run on an iOS 8 device it works as expected. Expect an issue created with full details in the next 24 hours in GitHub (I will also be attempting to resolve it). I should be also able to test against 8.4 sdk on Monday (CI environment still 8.4 sdk).

          • Hi Greg, the issue has a fix that’s already in GitHub. I’ve confirmed it works for both iOS 8 & 9. Pull down the latest and verify. Thanks!

            https://github.com/SharpMobileCode/ModalPickerViewController/issues/13

  • Ester Beltrami

    This solutions is very smart and easy. Just one thing: I would like to implement a custom PickerView, with a Lisit and I would like to select one of this. I try to explain better: for example I have a list of color in my List and the user selected ‘blue’ one time before. When The user taps on my UITextView I would like to show the pickerView whit the color ‘blue’ that is in the middle of the List… By default now it will select the first element of the list.

    How I can do this?

    Thanks. Ester

  • xleon

    This has been very useful. Thanks

  • Luis Garzon

    Is there any way to put the example in Spanish?

    • Hi! I’m not sure if you mean the sample code or the actual blog post, but I don’t Spanish in order to translate. However, I am open to anyone who wants to volunteer in translating it to Spanish.

      • Luis Garzon

        I only need that the months on the control appears in spanish. Thnaks

        • Take a look at the sample code. You can populate the picker with any thing you want. So if the months need to be in Spanish, populate them in Spanish. I designed it to be flexible that way.

          • Luis Garzon

            Where in the code do I make changes so moths are in spanish?

  • Sarath Nagesh

    Thank you. Very nice tool.

    But sometimes I am having this issue, where the previous ViewController View Shows up in the background when the picker open.. more like a ghosting issue. Please tell me what I can do to solve this

  • vic

    How do you make the customPicker work with a press on the textfield instead of a button press?