├── .gitignore ├── ModalPickerSample ├── AppDelegate.cs ├── Entitlements.plist ├── Info.plist ├── Main.cs ├── MainStoryboard.storyboard ├── ModalPickerSample.csproj ├── ModalPickerSample.sln ├── ModalPickerSample.userprefs ├── ModalPickerSampleViewController.cs ├── ModalPickerSampleViewController.designer.cs └── Resources │ └── Default-568h@2x.png ├── README.md └── SharpMobileCode.ModalPicker ├── CustomPickerModel.cs ├── ModalPickerAnimatedDismissed.cs ├── ModalPickerAnimatedTransitioning.cs ├── ModalPickerTransitionDelegate.cs ├── ModalPickerViewController.cs ├── Properties └── AssemblyInfo.cs └── SharpMobileCode.ModalPicker.csproj /.gitignore: -------------------------------------------------------------------------------- 1 | */bin/* 2 | */obj/* 3 | */*/bin/* 4 | */*/obj/* 5 | */*/bin/*/* 6 | */*/obj/*/* 7 | 8 | *.dll 9 | 10 | *.mdb 11 | 12 | *.exe 13 | 14 | *.mdb 15 | 16 | *.dll 17 | 18 | *.mdb 19 | 20 | *.userprefs 21 | -------------------------------------------------------------------------------- /ModalPickerSample/AppDelegate.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 3 | * Author: Ruben Macias 4 | * http://sharpmobilecode.com @SharpMobileCode 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | */ 19 | 20 | using System; 21 | using System.Collections.Generic; 22 | using System.Linq; 23 | 24 | using Foundation; 25 | using UIKit; 26 | 27 | namespace ModalPickerSample 28 | { 29 | // The UIApplicationDelegate for the application. This class is responsible for launching the 30 | // User Interface of the application, as well as listening (and optionally responding) to 31 | // application events from iOS. 32 | [Register("AppDelegate")] 33 | public partial class AppDelegate : UIApplicationDelegate 34 | { 35 | // class-level declarations 36 | 37 | public override UIWindow Window 38 | { 39 | get; 40 | set; 41 | } 42 | 43 | // This method is invoked when the application is about to move from active to inactive state. 44 | // OpenGL applications should use this method to pause. 45 | public override void OnResignActivation(UIApplication application) 46 | { 47 | } 48 | 49 | // This method should be used to release shared resources and it should store the application state. 50 | // If your application supports background exection this method is called instead of WillTerminate 51 | // when the user quits. 52 | public override void DidEnterBackground(UIApplication application) 53 | { 54 | } 55 | 56 | // This method is called as part of the transiton from background to active state. 57 | public override void WillEnterForeground(UIApplication application) 58 | { 59 | } 60 | 61 | // This method is called when the application is about to terminate. Save data, if needed. 62 | public override void WillTerminate(UIApplication application) 63 | { 64 | } 65 | } 66 | } 67 | 68 | -------------------------------------------------------------------------------- /ModalPickerSample/Entitlements.plist: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /ModalPickerSample/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDisplayName 6 | ModalPickerSample 7 | CFBundleIdentifier 8 | com.your-company.ModalPickerSample 9 | CFBundleShortVersionString 10 | 1.0 11 | CFBundleVersion 12 | 1.0 13 | LSRequiresIPhoneOS 14 | 15 | MinimumOSVersion 16 | 7.0 17 | UIDeviceFamily 18 | 19 | 1 20 | 2 21 | 22 | UIMainStoryboardFile 23 | MainStoryboard 24 | UIRequiredDeviceCapabilities 25 | 26 | armv7 27 | 28 | UISupportedInterfaceOrientations 29 | 30 | UIInterfaceOrientationPortrait 31 | UIInterfaceOrientationLandscapeLeft 32 | UIInterfaceOrientationLandscapeRight 33 | 34 | UIMainStoryboardFile~ipad 35 | MainStoryboard 36 | UISupportedInterfaceOrientations~ipad 37 | 38 | UIInterfaceOrientationPortrait 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /ModalPickerSample/Main.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 3 | * Author: Ruben Macias 4 | * http://sharpmobilecode.com @SharpMobileCode 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | */ 19 | 20 | using System; 21 | using System.Collections.Generic; 22 | using System.Linq; 23 | 24 | using Foundation; 25 | using UIKit; 26 | 27 | namespace ModalPickerSample 28 | { 29 | public class Application 30 | { 31 | // This is the main entry point of the application. 32 | static void Main(string[] args) 33 | { 34 | // if you want to use a different Application Delegate class from "AppDelegate" 35 | // you can specify it here. 36 | UIApplication.Main(args, null, "AppDelegate"); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /ModalPickerSample/MainStoryboard.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 30 | 42 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /ModalPickerSample/ModalPickerSample.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Debug 5 | iPhoneSimulator 6 | {FEACFBD2-3405-455C-9665-78FE426C6842};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 7 | {2570ED82-4EE9-4198-91A9-F4D0211AA973} 8 | Exe 9 | ModalPickerSample 10 | Resources 11 | ModalPickerSample 12 | Xamarin.iOS 13 | v1.0 14 | 15 | 16 | true 17 | full 18 | false 19 | bin\iPhoneSimulator\Debug 20 | DEBUG; 21 | prompt 22 | 4 23 | false 24 | None 25 | true 26 | iPhone Developer 27 | 28 | 29 | i386 30 | true 31 | 32 | 33 | full 34 | true 35 | bin\iPhoneSimulator\Release 36 | prompt 37 | 4 38 | None 39 | false 40 | Entitlements.plist 41 | 42 | 43 | i386 44 | 45 | 46 | true 47 | full 48 | false 49 | bin\iPhone\Debug 50 | DEBUG; 51 | prompt 52 | 4 53 | false 54 | Entitlements.plist 55 | true 56 | iPhone Developer 57 | ARMv7, ARMv7s, ARM64 58 | true 59 | true 60 | 61 | 62 | 63 | 64 | true 65 | 66 | 67 | full 68 | true 69 | bin\iPhone\Release 70 | prompt 71 | 4 72 | Entitlements.plist 73 | false 74 | iPhone Developer 75 | ARMv7, ARM64 76 | 77 | 78 | full 79 | true 80 | bin\iPhone\Ad-Hoc 81 | prompt 82 | 4 83 | false 84 | Entitlements.plist 85 | true 86 | Automatic:AdHoc 87 | iPhone Distribution 88 | ARMv7, ARM64 89 | 90 | 91 | 92 | 93 | full 94 | true 95 | bin\iPhone\AppStore 96 | prompt 97 | 4 98 | iPhone Distribution 99 | Entitlements.plist 100 | false 101 | Automatic:AppStore 102 | ARMv7, ARM64 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | ModalPickerSampleViewController.cs 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | {D8D8ED2E-2C43-416B-8196-46A0AD9788FD} 134 | SharpMobileCode.ModalPicker 135 | 136 | 137 | -------------------------------------------------------------------------------- /ModalPickerSample/ModalPickerSample.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2012 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ModalPickerSample", "ModalPickerSample.csproj", "{2570ED82-4EE9-4198-91A9-F4D0211AA973}" 5 | EndProject 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpMobileCode.ModalPicker", "..\SharpMobileCode.ModalPicker\SharpMobileCode.ModalPicker.csproj", "{D8D8ED2E-2C43-416B-8196-46A0AD9788FD}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|iPhoneSimulator = Debug|iPhoneSimulator 11 | Release|iPhoneSimulator = Release|iPhoneSimulator 12 | Debug|iPhone = Debug|iPhone 13 | Release|iPhone = Release|iPhone 14 | Ad-Hoc|iPhone = Ad-Hoc|iPhone 15 | AppStore|iPhone = AppStore|iPhone 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {2570ED82-4EE9-4198-91A9-F4D0211AA973}.Ad-Hoc|iPhone.ActiveCfg = Ad-Hoc|iPhone 19 | {2570ED82-4EE9-4198-91A9-F4D0211AA973}.Ad-Hoc|iPhone.Build.0 = Ad-Hoc|iPhone 20 | {2570ED82-4EE9-4198-91A9-F4D0211AA973}.AppStore|iPhone.ActiveCfg = AppStore|iPhone 21 | {2570ED82-4EE9-4198-91A9-F4D0211AA973}.AppStore|iPhone.Build.0 = AppStore|iPhone 22 | {2570ED82-4EE9-4198-91A9-F4D0211AA973}.Debug|iPhone.ActiveCfg = Debug|iPhone 23 | {2570ED82-4EE9-4198-91A9-F4D0211AA973}.Debug|iPhone.Build.0 = Debug|iPhone 24 | {2570ED82-4EE9-4198-91A9-F4D0211AA973}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator 25 | {2570ED82-4EE9-4198-91A9-F4D0211AA973}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator 26 | {2570ED82-4EE9-4198-91A9-F4D0211AA973}.Release|iPhone.ActiveCfg = Release|iPhone 27 | {2570ED82-4EE9-4198-91A9-F4D0211AA973}.Release|iPhone.Build.0 = Release|iPhone 28 | {2570ED82-4EE9-4198-91A9-F4D0211AA973}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator 29 | {2570ED82-4EE9-4198-91A9-F4D0211AA973}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator 30 | {D8D8ED2E-2C43-416B-8196-46A0AD9788FD}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU 31 | {D8D8ED2E-2C43-416B-8196-46A0AD9788FD}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU 32 | {D8D8ED2E-2C43-416B-8196-46A0AD9788FD}.AppStore|iPhone.ActiveCfg = Release|Any CPU 33 | {D8D8ED2E-2C43-416B-8196-46A0AD9788FD}.AppStore|iPhone.Build.0 = Release|Any CPU 34 | {D8D8ED2E-2C43-416B-8196-46A0AD9788FD}.Debug|iPhone.ActiveCfg = Debug|Any CPU 35 | {D8D8ED2E-2C43-416B-8196-46A0AD9788FD}.Debug|iPhone.Build.0 = Debug|Any CPU 36 | {D8D8ED2E-2C43-416B-8196-46A0AD9788FD}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU 37 | {D8D8ED2E-2C43-416B-8196-46A0AD9788FD}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU 38 | {D8D8ED2E-2C43-416B-8196-46A0AD9788FD}.Release|iPhone.ActiveCfg = Release|Any CPU 39 | {D8D8ED2E-2C43-416B-8196-46A0AD9788FD}.Release|iPhone.Build.0 = Release|Any CPU 40 | {D8D8ED2E-2C43-416B-8196-46A0AD9788FD}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU 41 | {D8D8ED2E-2C43-416B-8196-46A0AD9788FD}.Release|iPhoneSimulator.Build.0 = Release|Any CPU 42 | EndGlobalSection 43 | GlobalSection(MonoDevelopProperties) = preSolution 44 | StartupItem = ModalPickerSample.csproj 45 | EndGlobalSection 46 | EndGlobal 47 | -------------------------------------------------------------------------------- /ModalPickerSample/ModalPickerSample.userprefs: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /ModalPickerSample/ModalPickerSampleViewController.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 3 | * Author: Ruben Macias 4 | * http://sharpmobilecode.com @SharpMobileCode 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | */ 19 | 20 | using System; 21 | using System.Collections.Generic; 22 | 23 | using UIKit; 24 | 25 | using SharpMobileCode.ModalPicker; 26 | using Foundation; 27 | using CoreGraphics; 28 | 29 | namespace ModalPickerSample 30 | { 31 | public partial class ModalPickerSampleViewController : UIViewController 32 | { 33 | private DateTime[] _customDates; 34 | 35 | public ModalPickerSampleViewController(IntPtr handle) : base(handle) 36 | { 37 | Initialize(); 38 | } 39 | 40 | private void Initialize() 41 | { 42 | _customDates = new DateTime[] 43 | { 44 | DateTime.Now, DateTime.Now.AddDays(7), DateTime.Now.AddDays(7*2), 45 | DateTime.Now.AddDays(7*3), DateTime.Now.AddDays(7*4), DateTime.Now.AddDays(7*5), 46 | DateTime.Now.AddDays(7*6), DateTime.Now.AddDays(7*7), DateTime.Now.AddDays(7*8), 47 | DateTime.Now.AddDays(7*9), DateTime.Now.AddDays(7*10), DateTime.Now.AddDays(7*11), 48 | DateTime.Now.AddDays(7*12), DateTime.Now.AddDays(7*13), DateTime.Now.AddDays(7*14) 49 | }; 50 | } 51 | 52 | 53 | public override void ViewDidLoad() 54 | { 55 | base.ViewDidLoad(); 56 | 57 | DatePickerButton.TouchUpInside += DatePickerButtonTapped; 58 | CustomPickerButton.TouchUpInside += CustomPickerButtonTapped; 59 | SelectDateTextField.ShouldBeginEditing += OnTextFieldShouldBeginEditing; 60 | } 61 | 62 | async void DatePickerButtonTapped (object sender, EventArgs e) 63 | { 64 | var modalPicker = new ModalPickerViewController(ModalPickerType.Date, "Select A Date", this) 65 | { 66 | HeaderBackgroundColor = UIColor.Red, 67 | HeaderTextColor = UIColor.White, 68 | TransitioningDelegate = new ModalPickerTransitionDelegate(), 69 | ModalPresentationStyle = UIModalPresentationStyle.Custom 70 | }; 71 | 72 | modalPicker.DatePicker.Mode = UIDatePickerMode.Date; 73 | 74 | modalPicker.OnModalPickerDismissed += (s, ea) => 75 | { 76 | var dateFormatter = new NSDateFormatter() 77 | { 78 | DateFormat = "MMMM dd, yyyy" 79 | }; 80 | 81 | PickedLabel.Text = dateFormatter.ToString(modalPicker.DatePicker.Date); 82 | }; 83 | 84 | await PresentViewControllerAsync(modalPicker, true); 85 | } 86 | 87 | async void CustomPickerButtonTapped (object sender, EventArgs e) 88 | { 89 | //Create custom data source 90 | var customDatesList = new List(); 91 | foreach(var date in _customDates) 92 | { 93 | customDatesList.Add(date.ToString("ddd, MMM dd, yyyy")); 94 | } 95 | 96 | //Create the modal picker and style it as you see fit 97 | var modalPicker = new ModalPickerViewController(ModalPickerType.Custom, "Select A Date", this) 98 | { 99 | HeaderBackgroundColor = UIColor.Blue, 100 | HeaderTextColor = UIColor.White, 101 | TransitioningDelegate = new ModalPickerTransitionDelegate(), 102 | ModalPresentationStyle = UIModalPresentationStyle.Custom 103 | }; 104 | 105 | //Create the model for the Picker View 106 | modalPicker.PickerView.Model = new CustomPickerModel(customDatesList); 107 | 108 | //On an item is selected, update our label with the selected item. 109 | modalPicker.OnModalPickerDismissed += (s, ea) => 110 | { 111 | var index = modalPicker.PickerView.SelectedRowInComponent(0); 112 | PickedLabel.Text = customDatesList[(int)index]; 113 | }; 114 | 115 | await PresentViewControllerAsync(modalPicker, true); 116 | } 117 | 118 | bool OnTextFieldShouldBeginEditing(UITextField textField) 119 | { 120 | var modalPicker = new ModalPickerViewController(ModalPickerType.Date, "Select A Date", this) 121 | { 122 | HeaderBackgroundColor = UIColor.Red, 123 | HeaderTextColor = UIColor.White, 124 | TransitioningDelegate = new ModalPickerTransitionDelegate(), 125 | ModalPresentationStyle = UIModalPresentationStyle.Custom 126 | }; 127 | 128 | modalPicker.DatePicker.Mode = UIDatePickerMode.Date; 129 | 130 | modalPicker.OnModalPickerDismissed += (s, ea) => 131 | { 132 | var dateFormatter = new NSDateFormatter() 133 | { 134 | DateFormat = "MMMM dd, yyyy" 135 | }; 136 | 137 | textField.Text = dateFormatter.ToString(modalPicker.DatePicker.Date); 138 | }; 139 | 140 | PresentViewController(modalPicker, true, null); 141 | 142 | return false; 143 | } 144 | } 145 | } 146 | 147 | -------------------------------------------------------------------------------- /ModalPickerSample/ModalPickerSampleViewController.designer.cs: -------------------------------------------------------------------------------- 1 | // WARNING 2 | // 3 | // This file has been generated automatically by Xamarin Studio from the outlets and 4 | // actions declared in your storyboard file. 5 | // Manual changes to this file will not be maintained. 6 | // 7 | using Foundation; 8 | using System; 9 | using System.CodeDom.Compiler; 10 | using UIKit; 11 | 12 | namespace ModalPickerSample 13 | { 14 | [Register ("ModalPickerSampleViewController")] 15 | partial class ModalPickerSampleViewController 16 | { 17 | [Outlet] 18 | [GeneratedCode ("iOS Designer", "1.0")] 19 | UIButton CustomPickerButton { get; set; } 20 | 21 | [Outlet] 22 | [GeneratedCode ("iOS Designer", "1.0")] 23 | UIButton DatePickerButton { get; set; } 24 | 25 | [Outlet] 26 | [GeneratedCode ("iOS Designer", "1.0")] 27 | UILabel PickedLabel { get; set; } 28 | 29 | [Outlet] 30 | [GeneratedCode ("iOS Designer", "1.0")] 31 | UITextField SelectDateTextField { get; set; } 32 | 33 | void ReleaseDesignerOutlets () 34 | { 35 | if (CustomPickerButton != null) { 36 | CustomPickerButton.Dispose (); 37 | CustomPickerButton = null; 38 | } 39 | if (DatePickerButton != null) { 40 | DatePickerButton.Dispose (); 41 | DatePickerButton = null; 42 | } 43 | if (PickedLabel != null) { 44 | PickedLabel.Dispose (); 45 | PickedLabel = null; 46 | } 47 | if (SelectDateTextField != null) { 48 | SelectDateTextField.Dispose (); 49 | SelectDateTextField = null; 50 | } 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /ModalPickerSample/Resources/Default-568h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SharpMobileCode/ModalPickerViewController/01bed34410d44f348fc9e4e9562bdb794a2c2ba8/ModalPickerSample/Resources/Default-568h@2x.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ModalPickerViewController 2 | =========== 3 | 4 | **Update: Now supports 64-bit Unified API!** 5 | 6 | The ModalPickerViewController is a view controller that is designed to replace [ActionSheetDatePicker](http://developer.xamarin.com/recipes/ios/standard_controls/actionsheet/actionsheet_date_picker/). The ActionSheetDatePicker was an example provided by Xamarin to show a nice looking Date Picker that did not take up the whole screen. 7 | 8 | Though this did do the job, the UIActionSheet was not designed to be subclassed or views added to its hierarchy. Starting with iOS 7, Apple started issuing runtime warnings, but did not crash the app. The warnings looked something like this: 9 | 10 | > Error: CGContextSetFillColorWithColor: invalid context 0x0. This is a serious error. 11 | > This application, or a library it uses, is using an invalid context and is thereby contributing 12 | > to an overall degradation of system stability and reliability. 13 | > This notice is a courtesy: please fix this problem. 14 | > It will become a fatal error in an upcoming update. 15 | 16 | Notice the last two lines of the warning. Apple was warning developers in iOS 7 that this was not the way the UIActionSheet was intended to be used, and that it will **BREAK** in a future version of iOS. Well, it now crashes on iOS 8. 17 | 18 | ![Date Picker Screenshot](http://sharpmobilecode.com/wp-content/uploads/2014/09/DatePicker.png)![Custom Picker Screenshot](http://sharpmobilecode.com/wp-content/uploads/2014/09/CustomPicker.png) 19 | 20 | ## Example Usage 21 | Please see the blog post at [http://sharpmobilecode.com/a-replacement-for-actionsheet-date-picker/](http://sharpmobilecode.com/a-replacement-for-actionsheet-date-picker/) for example usage 22 | 23 | ## Areas For Improvement 24 | When you rotate between Portrait and Landscape, the transition is not as smooth as I would like it to be. Feel free to submit a pull request and take a shot at it! :) 25 | 26 | ## Contributors 27 | Ruben Macias @sharpmobilecode 28 | 29 | ## License 30 | Licensed under the [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.html) 31 | 32 | -------------------------------------------------------------------------------- /SharpMobileCode.ModalPicker/CustomPickerModel.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 3 | * Author: Ruben Macias 4 | * http://sharpmobilecode.com @SharpMobileCode 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | */ 19 | 20 | using System; 21 | using UIKit; 22 | using CoreGraphics; 23 | using System.Collections.Generic; 24 | 25 | namespace SharpMobileCode.ModalPicker 26 | { 27 | public class CustomPickerModel : UIPickerViewModel 28 | { 29 | private List _itemsList; 30 | 31 | public CustomPickerModel(List itemsList) 32 | { 33 | _itemsList = itemsList; 34 | } 35 | 36 | public override nint GetComponentCount(UIPickerView picker) 37 | { 38 | return 1; 39 | } 40 | 41 | public override nint GetRowsInComponent(UIPickerView picker, nint component) 42 | { 43 | return _itemsList.Count; 44 | } 45 | 46 | public override UIView GetView(UIPickerView picker, nint row, nint component, UIView view) 47 | { 48 | var label = new UILabel(new CGRect(0, 0, 300, 37)) 49 | { 50 | BackgroundColor = UIColor.Clear, 51 | Text = _itemsList[(int)row], 52 | TextAlignment = UITextAlignment.Center, 53 | Font = UIFont.BoldSystemFontOfSize(22.0f) 54 | }; 55 | 56 | return label; 57 | } 58 | } 59 | } 60 | 61 | -------------------------------------------------------------------------------- /SharpMobileCode.ModalPicker/ModalPickerAnimatedDismissed.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 3 | * Author: Ruben Macias 4 | * http://sharpmobilecode.com @SharpMobileCode 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | */ 19 | 20 | using System; 21 | using UIKit; 22 | using CoreGraphics; 23 | 24 | namespace SharpMobileCode.ModalPicker 25 | { 26 | public class ModalPickerAnimatedDismissed : UIViewControllerAnimatedTransitioning 27 | { 28 | public bool IsPresenting { get; set; } 29 | float _transitionDuration = 0.25f; 30 | 31 | public ModalPickerAnimatedDismissed() 32 | { 33 | } 34 | 35 | public override double TransitionDuration(IUIViewControllerContextTransitioning transitionContext) 36 | { 37 | return _transitionDuration; 38 | } 39 | 40 | public override void AnimateTransition(IUIViewControllerContextTransitioning transitionContext) 41 | { 42 | 43 | var fromViewController = transitionContext.GetViewControllerForKey(UITransitionContext.FromViewControllerKey); 44 | var toViewController = transitionContext.GetViewControllerForKey(UITransitionContext.ToViewControllerKey); 45 | 46 | var screenBounds = UIScreen.MainScreen.Bounds; 47 | var fromFrame = fromViewController.View.Frame; 48 | 49 | UIView.AnimateNotify(_transitionDuration, 50 | () => 51 | { 52 | toViewController.View.Alpha = 1.0f; 53 | 54 | switch(fromViewController.InterfaceOrientation) 55 | { 56 | case UIInterfaceOrientation.Portrait: 57 | fromViewController.View.Frame = new CGRect(0, screenBounds.Height, fromFrame.Width, fromFrame.Height); 58 | break; 59 | case UIInterfaceOrientation.LandscapeLeft: 60 | fromViewController.View.Frame = new CGRect(screenBounds.Width, 0, fromFrame.Width, fromFrame.Height); 61 | break; 62 | case UIInterfaceOrientation.LandscapeRight: 63 | fromViewController.View.Frame = new CGRect(screenBounds.Width * -1, 0, fromFrame.Width, fromFrame.Height); 64 | break; 65 | default: 66 | break; 67 | } 68 | 69 | }, 70 | (finished) => transitionContext.CompleteTransition(true)); 71 | } 72 | } 73 | } 74 | 75 | -------------------------------------------------------------------------------- /SharpMobileCode.ModalPicker/ModalPickerAnimatedTransitioning.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 3 | * Author: Ruben Macias 4 | * http://sharpmobilecode.com @SharpMobileCode 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | */ 19 | 20 | using System; 21 | using UIKit; 22 | using CoreGraphics; 23 | 24 | namespace SharpMobileCode.ModalPicker 25 | { 26 | public class ModalPickerAnimatedTransitioning : UIViewControllerAnimatedTransitioning 27 | { 28 | public bool IsPresenting { get; set; } 29 | 30 | float _transitionDuration = 0.25f; 31 | 32 | public ModalPickerAnimatedTransitioning() 33 | { 34 | 35 | } 36 | 37 | public override double TransitionDuration(IUIViewControllerContextTransitioning transitionContext) 38 | { 39 | return _transitionDuration; 40 | } 41 | 42 | public override void AnimateTransition(IUIViewControllerContextTransitioning transitionContext) 43 | { 44 | var inView = transitionContext.ContainerView; 45 | 46 | var toViewController = transitionContext.GetViewControllerForKey(UITransitionContext.ToViewControllerKey); 47 | var fromViewController = transitionContext.GetViewControllerForKey(UITransitionContext.FromViewControllerKey); 48 | 49 | inView.AddSubview(toViewController.View); 50 | 51 | toViewController.View.Frame = CGRect.Empty; 52 | 53 | var startingPoint = GetStartingPoint(fromViewController.InterfaceOrientation); 54 | if (fromViewController.InterfaceOrientation == UIInterfaceOrientation.Portrait) 55 | { 56 | toViewController.View.Frame = new CGRect(startingPoint.X, startingPoint.Y, 57 | fromViewController.View.Frame.Width, 58 | fromViewController.View.Frame.Height); 59 | } 60 | else 61 | { 62 | toViewController.View.Frame = new CGRect(startingPoint.X, startingPoint.Y, 63 | fromViewController.View.Frame.Height, 64 | fromViewController.View.Frame.Width); 65 | } 66 | 67 | UIView.AnimateNotify(_transitionDuration, 68 | () => 69 | { 70 | var endingPoint = GetEndingPoint(fromViewController.InterfaceOrientation); 71 | toViewController.View.Frame = new CGRect(endingPoint.X, endingPoint.Y, fromViewController.View.Frame.Width, 72 | fromViewController.View.Frame.Height); 73 | fromViewController.View.Alpha = 0.5f; 74 | }, 75 | (finished) => transitionContext.CompleteTransition(true) 76 | ); 77 | } 78 | 79 | CGPoint GetStartingPoint(UIInterfaceOrientation orientation) 80 | { 81 | var screenBounds = UIScreen.MainScreen.Bounds; 82 | var coordinate = CGPoint.Empty; 83 | switch(orientation) 84 | { 85 | case UIInterfaceOrientation.Portrait: 86 | coordinate = new CGPoint(0, screenBounds.Height); 87 | break; 88 | case UIInterfaceOrientation.LandscapeLeft: 89 | coordinate = new CGPoint(screenBounds.Width, 0); 90 | break; 91 | case UIInterfaceOrientation.LandscapeRight: 92 | coordinate = new CGPoint(screenBounds.Width * -1, 0); 93 | break; 94 | default: 95 | coordinate = new CGPoint(0, screenBounds.Height); 96 | break; 97 | } 98 | 99 | return coordinate; 100 | } 101 | 102 | CGPoint GetEndingPoint(UIInterfaceOrientation orientation) 103 | { 104 | var screenBounds = UIScreen.MainScreen.Bounds; 105 | var coordinate = CGPoint.Empty; 106 | switch(orientation) 107 | { 108 | case UIInterfaceOrientation.Portrait: 109 | coordinate = new CGPoint(0, 0); 110 | break; 111 | case UIInterfaceOrientation.LandscapeLeft: 112 | coordinate = new CGPoint(0, 0); 113 | break; 114 | case UIInterfaceOrientation.LandscapeRight: 115 | coordinate = new CGPoint(0, 0); 116 | break; 117 | default: 118 | coordinate = new CGPoint(0, 0); 119 | break; 120 | } 121 | 122 | return coordinate; 123 | } 124 | } 125 | } 126 | 127 | -------------------------------------------------------------------------------- /SharpMobileCode.ModalPicker/ModalPickerTransitionDelegate.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 3 | * Author: Ruben Macias 4 | * http://sharpmobilecode.com @SharpMobileCode 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | */ 19 | 20 | using System; 21 | using UIKit; 22 | 23 | namespace SharpMobileCode.ModalPicker 24 | { 25 | public class ModalPickerTransitionDelegate : UIViewControllerTransitioningDelegate 26 | { 27 | public ModalPickerTransitionDelegate() 28 | { 29 | } 30 | 31 | public override IUIViewControllerAnimatedTransitioning GetAnimationControllerForPresentedController(UIViewController presented, UIViewController presenting, UIViewController source) 32 | { 33 | var controller = new ModalPickerAnimatedTransitioning(); 34 | controller.IsPresenting = true; 35 | 36 | return controller; 37 | } 38 | 39 | public override IUIViewControllerAnimatedTransitioning GetAnimationControllerForDismissedController(UIViewController dismissed) 40 | { 41 | var controller = new ModalPickerAnimatedDismissed(); 42 | controller.IsPresenting = false; 43 | 44 | return controller; 45 | } 46 | 47 | public override IUIViewControllerInteractiveTransitioning GetInteractionControllerForPresentation(IUIViewControllerAnimatedTransitioning animator) 48 | { 49 | return null; 50 | } 51 | 52 | public override IUIViewControllerInteractiveTransitioning GetInteractionControllerForDismissal(IUIViewControllerAnimatedTransitioning animator) 53 | { 54 | return null; 55 | } 56 | 57 | } 58 | } 59 | 60 | -------------------------------------------------------------------------------- /SharpMobileCode.ModalPicker/ModalPickerViewController.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 3 | * Author: Ruben Macias 4 | * http://sharpmobilecode.com @SharpMobileCode 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | */ 19 | 20 | using System; 21 | using UIKit; 22 | using CoreGraphics; 23 | 24 | namespace SharpMobileCode.ModalPicker 25 | { 26 | public delegate void ModalPickerDimissedEventHandler(object sender, EventArgs e); 27 | 28 | public class ModalPickerViewController : UIViewController 29 | { 30 | public event ModalPickerDimissedEventHandler OnModalPickerDismissed; 31 | const float _headerBarHeight = 40; 32 | 33 | public UIColor HeaderBackgroundColor { get; set; } 34 | public UIColor HeaderTextColor { get; set; } 35 | public string HeaderText { get; set; } 36 | public string DoneButtonText { get; set; } 37 | public string CancelButtonText { get; set; } 38 | 39 | public UIDatePicker DatePicker { get; set; } 40 | public UIPickerView PickerView { get; set; } 41 | private ModalPickerType _pickerType; 42 | public ModalPickerType PickerType 43 | { 44 | get { return _pickerType; } 45 | set 46 | { 47 | switch(value) 48 | { 49 | case ModalPickerType.Date: 50 | DatePicker = new UIDatePicker(CGRect.Empty); 51 | PickerView = null; 52 | break; 53 | case ModalPickerType.Custom: 54 | DatePicker = null; 55 | PickerView = new UIPickerView(CGRect.Empty); 56 | break; 57 | default: 58 | break; 59 | } 60 | 61 | _pickerType = value; 62 | } 63 | } 64 | 65 | UILabel _headerLabel; 66 | UIButton _doneButton; 67 | UIButton _cancelButton; 68 | UIViewController _parent; 69 | UIView _internalView; 70 | 71 | public ModalPickerViewController(ModalPickerType pickerType, string headerText, UIViewController parent) 72 | { 73 | HeaderBackgroundColor = UIColor.White; 74 | HeaderTextColor = UIColor.Black; 75 | HeaderText = headerText; 76 | PickerType = pickerType; 77 | _parent = parent; 78 | DoneButtonText = "Done"; 79 | CancelButtonText = "Cancel"; 80 | } 81 | 82 | public override void ViewDidLoad() 83 | { 84 | base.ViewDidLoad(); 85 | 86 | InitializeControls(); 87 | } 88 | 89 | public override void ViewWillAppear(bool animated) 90 | { 91 | base.ViewDidAppear(animated); 92 | 93 | Show(); 94 | } 95 | 96 | void InitializeControls() 97 | { 98 | View.BackgroundColor = UIColor.Clear; 99 | _internalView = new UIView(); 100 | 101 | _headerLabel = new UILabel(new CGRect(0, 0, 320/2, 44)); 102 | _headerLabel.AutoresizingMask = UIViewAutoresizing.FlexibleWidth; 103 | _headerLabel.BackgroundColor = HeaderBackgroundColor; 104 | _headerLabel.TextColor = HeaderTextColor; 105 | _headerLabel.Text = HeaderText; 106 | _headerLabel.TextAlignment = UITextAlignment.Center; 107 | 108 | _cancelButton = UIButton.FromType(UIButtonType.System); 109 | _cancelButton.SetTitleColor(HeaderTextColor, UIControlState.Normal); 110 | _cancelButton.BackgroundColor = UIColor.Clear; 111 | _cancelButton.SetTitle(CancelButtonText, UIControlState.Normal); 112 | _cancelButton.TouchUpInside += CancelButtonTapped; 113 | 114 | _doneButton = UIButton.FromType(UIButtonType.System); 115 | _doneButton.SetTitleColor(HeaderTextColor, UIControlState.Normal); 116 | _doneButton.BackgroundColor = UIColor.Clear; 117 | _doneButton.SetTitle(DoneButtonText, UIControlState.Normal); 118 | _doneButton.TouchUpInside += DoneButtonTapped; 119 | 120 | switch(PickerType) 121 | { 122 | case ModalPickerType.Date: 123 | DatePicker.BackgroundColor = UIColor.White; 124 | _internalView.AddSubview(DatePicker); 125 | break; 126 | case ModalPickerType.Custom: 127 | PickerView.BackgroundColor = UIColor.White; 128 | _internalView.AddSubview(PickerView); 129 | break; 130 | default: 131 | break; 132 | } 133 | _internalView.BackgroundColor = HeaderBackgroundColor; 134 | 135 | _internalView.AddSubview(_headerLabel); 136 | _internalView.AddSubview (_cancelButton); 137 | _internalView.AddSubview(_doneButton); 138 | 139 | Add(_internalView); 140 | } 141 | 142 | void Show(bool onRotate = false) 143 | { 144 | var buttonSize = new CGSize(71, 30); 145 | 146 | var width = _parent.View.Frame.Width; 147 | 148 | var internalViewSize = CGSize.Empty; 149 | switch(_pickerType) 150 | { 151 | case ModalPickerType.Date: 152 | internalViewSize = new CGSize(width, DatePicker.Frame.Height + _headerBarHeight); 153 | break; 154 | case ModalPickerType.Custom: 155 | internalViewSize = new CGSize(width, PickerView.Frame.Height + _headerBarHeight); 156 | break; 157 | default: 158 | break; 159 | } 160 | 161 | var internalViewFrame = CGRect.Empty; 162 | if (InterfaceOrientation == UIInterfaceOrientation.Portrait) 163 | { 164 | if (onRotate) 165 | { 166 | internalViewFrame = new CGRect(0, View.Frame.Height - internalViewSize.Height, 167 | internalViewSize.Width, internalViewSize.Height); 168 | } 169 | else 170 | { 171 | internalViewFrame = new CGRect(0, View.Bounds.Height - internalViewSize.Height, 172 | internalViewSize.Width, internalViewSize.Height); 173 | } 174 | } 175 | else 176 | { 177 | if (onRotate) 178 | { 179 | internalViewFrame = new CGRect(0, View.Bounds.Height - internalViewSize.Height, 180 | internalViewSize.Width, internalViewSize.Height); 181 | } 182 | else 183 | { 184 | internalViewFrame = new CGRect(0, View.Frame.Height - internalViewSize.Height, 185 | internalViewSize.Width, internalViewSize.Height); 186 | } 187 | } 188 | _internalView.Frame = internalViewFrame; 189 | 190 | switch(_pickerType) 191 | { 192 | case ModalPickerType.Date: 193 | DatePicker.Frame = new CGRect(DatePicker.Frame.X, _headerBarHeight, _internalView.Frame.Width, 194 | DatePicker.Frame.Height); 195 | break; 196 | case ModalPickerType.Custom: 197 | PickerView.Frame = new CGRect(PickerView.Frame.X, _headerBarHeight, _internalView.Frame.Width, 198 | PickerView.Frame.Height); 199 | break; 200 | default: 201 | break; 202 | } 203 | 204 | _headerLabel.Frame = new CGRect(20+buttonSize.Width, 4, _parent.View.Frame.Width - (40+2*buttonSize.Width), 35); 205 | _doneButton.Frame = new CGRect(internalViewFrame.Width - buttonSize.Width - 10, 7, buttonSize.Width, buttonSize.Height); 206 | _cancelButton.Frame = new CGRect(10, 7, buttonSize.Width, buttonSize.Height); 207 | } 208 | 209 | void DoneButtonTapped (object sender, EventArgs e) 210 | { 211 | DismissViewController(true, null); 212 | if(OnModalPickerDismissed != null) 213 | { 214 | OnModalPickerDismissed(sender, e); 215 | } 216 | } 217 | 218 | void CancelButtonTapped (object sender, EventArgs e) 219 | { 220 | DismissViewController(true, null); 221 | } 222 | 223 | public override void DidRotate(UIInterfaceOrientation fromInterfaceOrientation) 224 | { 225 | base.DidRotate(fromInterfaceOrientation); 226 | 227 | if (InterfaceOrientation == UIInterfaceOrientation.Portrait || 228 | InterfaceOrientation == UIInterfaceOrientation.LandscapeLeft || 229 | InterfaceOrientation == UIInterfaceOrientation.LandscapeRight) 230 | { 231 | Show(true); 232 | View.SetNeedsDisplay(); 233 | } 234 | } 235 | } 236 | 237 | public enum ModalPickerType 238 | { 239 | Date = 0, 240 | Custom = 1 241 | } 242 | } 243 | 244 | -------------------------------------------------------------------------------- /SharpMobileCode.ModalPicker/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | 4 | // Information about this assembly is defined by the following attributes. 5 | // Change them to the values specific to your project. 6 | 7 | [assembly: AssemblyTitle("SharpMobileCode.ModalPicker")] 8 | [assembly: AssemblyDescription("")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("")] 11 | [assembly: AssemblyProduct("")] 12 | [assembly: AssemblyCopyright("rubenmacias")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". 17 | // The form "{Major}.{Minor}.*" will automatically update the build and revision, 18 | // and "{Major}.{Minor}.{Build}.*" will update just the revision. 19 | 20 | [assembly: AssemblyVersion("1.0.*")] 21 | 22 | // The following attributes are used to specify the signing key for the assembly, 23 | // if desired. See the Mono documentation for more information about signing. 24 | 25 | //[assembly: AssemblyDelaySign(false)] 26 | //[assembly: AssemblyKeyFile("")] 27 | 28 | -------------------------------------------------------------------------------- /SharpMobileCode.ModalPicker/SharpMobileCode.ModalPicker.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Debug 5 | AnyCPU 6 | {FEACFBD2-3405-455C-9665-78FE426C6842};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 7 | {D8D8ED2E-2C43-416B-8196-46A0AD9788FD} 8 | Library 9 | SharpMobileCode.ModalPicker 10 | Resources 11 | SharpMobileCode.ModalPicker 12 | Xamarin.iOS 13 | v1.0 14 | 15 | 16 | true 17 | full 18 | false 19 | bin\Debug 20 | DEBUG; 21 | prompt 22 | 4 23 | false 24 | 25 | 26 | full 27 | true 28 | bin\Release 29 | prompt 30 | 4 31 | false 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | --------------------------------------------------------------------------------