Popup picker in Xamarin iOS - ios

I need to implement a picker like in this image. How can I do this? I'm using Xamarin.iOS but I can use an answer with native code and translate it myself.

use an ActionSheet
actionSheetButton.TouchUpInside += ((sender, e) => {
// Create a new Alert Controller
UIAlertController actionSheetAlert = UIAlertController.Create("Action Sheet", "Select an item from below", UIAlertControllerStyle.ActionSheet);
// Add Actions
actionSheetAlert.AddAction(UIAlertAction.Create("Item One",UIAlertActionStyle.Default, (action) => Console.WriteLine ("Item One pressed.")));
actionSheetAlert.AddAction(UIAlertAction.Create("Item Two",UIAlertActionStyle.Default, (action) => Console.WriteLine ("Item Two pressed.")));
actionSheetAlert.AddAction(UIAlertAction.Create("Item Three",UIAlertActionStyle.Default, (action) => Console.WriteLine ("Item Three pressed.")));
actionSheetAlert.AddAction(UIAlertAction.Create("Cancel",UIAlertActionStyle.Cancel, (action) => Console.WriteLine ("Cancel button pressed.")));
// Required for iPad - You must specify a source for the Action Sheet since it is
// displayed as a popover
UIPopoverPresentationController presentationPopover = actionSheetAlert.PopoverPresentationController;
if (presentationPopover!=null) {
presentationPopover.SourceView = this.View;
presentationPopover.PermittedArrowDirections = UIPopoverArrowDirection.Up;
}
// Display the alert
this.PresentViewController(actionSheetAlert,true,null);
});

You can assign a PickerView to TextField's InputView property and assign a Toolbar to InputAccessoryView, like this:
UIToolbar toolBar = new UIToolbar(new CGRect(0, 0, 320, 44));
UIBarButtonItem flexibleSpaceLeft = new UIBarButtonItem(UIBarButtonSystemItem.FlexibleSpace,null,null);
UIBarButtonItem doneButton = new UIBarButtonItem("OK",UIBarButtonItemStyle.Done,this, new ObjCRuntime.Selector("DoneAction"));
UIBarButtonItem[] list = new UIBarButtonItem[] { flexibleSpaceLeft, doneButton };
toolBar.SetItems(list, false);
UIPickerView pickerView = new UIPickerView(new CGRect(0, 44, 320, 216));
pickerView.DataSource = new MyUIPickerViewDataSource();
pickerView.Delegate = new MyUIPickerViewDelegate();
pickerView.ShowSelectionIndicator = true;
textField.InputAccessoryView = toolBar;
textField.InputView = pickerView;
After you implement your DataSource and Delegate of the pickerview, it can work like this:

Thanks Kevin Li for the answer, just wanted to give a simplified version in case anyone needs this. Not exactly what was originally asked for, but does the job.
var pickerView = new UIPickerView();
var sports = new string[] { "baseball", "basketball", "wiener dog" };
var model = new PickerModel(sports);
model.PickerChanged += (sender, e) =>
{
txtSport.Text = sports[e.SelectedValue];
};
pickerView.Model = model;
pickerView.ShowSelectionIndicator = true;
// setting picker view to your textfield
txtSport.InputView = pickerView;

Related

UIPickerView not interactive

I have an application that from the main app "hamburger" menu, if an option is selected I want to show a PickerView for the user to select a number from.
Because it's needs to be accessible throughout the app from this menu I built the UIPickerView in the AppDelegate.cs (as that's where the UINavigationController code is and from that the menu).
Everything shows up correctly: User selected menu button -> menu displays -> User selects "Show Picker" button -> Picker displays with all items. But once the picker displays, you can't scroll the options, nor does the "Done" button I've added register clicks. In fact text fields from the ViewController behind this popup can be clicked on through the popup.
I'm not sure why this UIPickerView is non interactive, does anyone have some thoughts?
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
// create a new window instance based on the screen size
window = new UIWindow(UIScreen.MainScreen.Bounds);
// instantiate the navigation controller
nav = new UINavigationController(new SplashController());
vwNav = new UIView(nav.NavigationBar.Bounds);
var pickerView = new UIPickerView(new CGRect(275f, (UIScreen.MainScreen.Bounds.Size.Height / 2) - (375f / 2), 275f, 375f));
pickerView.ShowSelectionIndicator = true;
var myPickerViewModel = new PickerViewModel(itemList);
pickerView.Model = myPickerViewModel;
myPickerViewModel.PickerChanged += (sender, e) => {
var temp = myPickerViewModel.SelectedItem;
};
// Set up toolbar
var toolbar = new UIToolbar();
toolbar.SizeToFit();
toolbar.Hidden = false;
UILabel titleLabel = new UILabel();
titleLabel.Text = "Select an Item";
titleLabel.Frame = new RectangleF(75, 13, 200, 20);
UIButton doneButton = new UIButton(UIButtonType.Custom);
doneButton.Frame = new RectangleF(40, 335, (float)200, 30);
doneButton.SetTitle("Done", UIControlState.Normal);
doneButton.TouchDown += (sender, e) =>
{
pickerView.Hidden = true;
};
toolbar.AddSubview(titleLabel);
toolbar.AddSubview(doneButton);
pickerView.AddSubview(toolbar);
pickerView.Hidden = true;
btnMenu = new UIButton(UIButtonType.Custom);
btnMenu.Frame = new CGRect(vwNav.Frame.Right - 45, 0, 45, nav.NavigationBar.Bounds.Height);
btnMenu.SetImage(imgMenu, UIControlState.Normal);
btnMenu.SetImage(imgMenu, UIControlState.Selected);
btnMenu.TouchUpInside += (object sender, EventArgs e) =>
{
UIAlertView alert = new UIAlertView();
alert.Title = "Settings";
alert.AddButton("Open PickerView");
alert.AddButton("Exit");
alert.Dismissed += delegate (object alertSender, UIButtonEventArgs args)
{
if (args.ButtonIndex == 0)
{
pickerView.Hidden = false;
}
else
return;
}
}
vwNav.AddSubviews(btnMenu, pickerView);
nav.NavigationBar.Layer.BorderWidth = 2f;
nav.NavigationBar.Layer.BorderColor = (UIColor.FromPatternImage(imgNavBar)).CGColor;
nav.NavigationBar.AddSubviews(vwNav);
// If you have defined a root view controller, set it here:
this.window.RootViewController = nav;
this.window.MakeKeyAndVisible();
return true;
}
I removed some of the unrelated code (a few nav.PushViewController() for different screens and other menu options) to keep it as clear as I could.
From your code, the frame of vwNav is nav.NavigationBar.Bounds, and the frame of pickerView is new CGRect(275f, (UIScreen.MainScreen.Bounds.Size.Height / 2) - (375f / 2), 275f, 375f), if you add pickView to vwNav, the pickerView is out of bounds of vwNav.
Remember that views don't receive touch events where they're outside the bounds of their superview.
That's the cause of your issue.
Solution:
I don't think you should built the UIPickerView in the AppDelegate.cs, create it in your ViewController instead.
You can also add buttons to Navigationbar in ViewController :
UIBarButtonItem btn = new UIBarButtonItem();
btn.Image = UIImage.FromFile("Image");
btn.Clicked += (sender, e) => { System.Diagnostics.Debug.WriteLine("show picker"); };
NavigationItem.RightBarButtonItem = btn;
And remember to add picker to the View of Viewcontroller.
Refer: uinavigationitem and add-uibarbuttonitem-to-navigation-bar-in-xamarin-ios
Feel free to ask me any question:).

iOS 11 navigation bar / uibarbutton items rendering issues

I'm trying to add multiple UIBarButtonItem items to the left, and one on the right. This worked fine up through iOS10, but iOS11 seems to have broken it.
This is all written with Xamarin, but the class/method names, etc., just about all map up, so answer however you want.
When using the simplest approach possible to add two buttons, setting an image/action directly on the button, I only get one of the two, and it's huge, and centered, and my title is lost:
var leftMenuBarBackBtn = new UIBarButtonItem(UIImage.FromBundle("arrowBackButton"), UIBarButtonItemStyle.Plain, leftBackButtonTap);
var leftMenuBarItem = new UIBarButtonItem(UIImage.FromBundle("menu"), UIBarButtonItemStyle.Plain, leftMenuButtonTap);
UIBarButtonItem[] navItems = {
leftMenuBarBackBtn,
leftMenuBarItem
};
var rightMenuBarItem = new UIBarButtonItem(UIImage.FromBundle("bell").ImageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal), UIBarButtonItemStyle.Plain, rightMenuButtonTap);
NavigationItem.LeftItemsSupplementBackButton = false;
NavigationItem.LeftBarButtonItems = navItems;
NavigationItem.RightBarButtonItem = rightMenuBarItem;
Previously we were creating UIImage items and adding them as custom views (please ignore the horrible practices, this was inherited):
var leftBackBtn = new UIButton(UIButtonType.Custom);
leftBackBtn.SetImage(UIImage.FromBundle("arrowBackButton").ImageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal), UIControlState.Normal);
leftBackBtn.Frame = new CGRect(0, 0, 27, 20);
leftBackBtn.ContentMode = UIViewContentMode.ScaleAspectFit;
leftBackBtn.TouchUpInside += leftBackButtonTap;
UIBarButtonItem leftMenuBarBackBtn = new UIBarButtonItem(leftBackBtn);
var leftMenuBtn = new UIButton(UIButtonType.Custom);
leftMenuBtn.SetImage(UIImage.FromBundle("menu").ImageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal), UIControlState.Normal);
leftMenuBtn.Frame = new CGRect(0, 0, 27, 20);
leftMenuBtn.ContentMode = UIViewContentMode.ScaleAspectFit;
leftMenuBtn.TouchUpInside += leftMenuButtonTap;
UIBarButtonItem leftMenuBarItem = new UIBarButtonItem(leftMenuBtn);
UIBarButtonItem[] navItems = { leftMenuBarBackBtn, leftMenuBarItem };
var rightMenuBtn = new UIButton(UIButtonType.Custom);
rightMenuBtn.SetImage(UIImage.FromBundle("bell").ImageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal), UIControlState.Normal);
rightMenuBtn.Frame = new CGRect(0, 0, 19, 22);
rightMenuBtn.ContentMode = UIViewContentMode.ScaleAspectFit;
rightMenuBtn.TouchUpInside += rightMenuButtonTap;
UIBarButtonItem righttMenuBarItem = new UIBarButtonItem(rightMenuBtn);
UIBarButtonItem[] navItems2 = { righttMenuBarItem };
this.NavigationItem.LeftBarButtonItems = navItems;
this.NavigationItem.RightBarButtonItems = navItems2;
I get a weird, stretched out 'back' button, and an extremely tiny hamburger menu:
Lastly, though I disagree with it, our client was insistent on a custom back button. When I went with what I would think is the proper approach, using the native back button, it somewhat works, and my title view is back. This'll work as a stop-gap but it's not really the UX we want:
var leftMenuBarItem = new UIBarButtonItem(UIImage.FromBundle("menu"), UIBarButtonItemStyle.Plain, leftMenuButtonTap);
var rightMenuBarItem = new UIBarButtonItem(UIImage.FromBundle("bell").ImageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal), UIBarButtonItemStyle.Plain, rightMenuButtonTap);
NavigationItem.LeftItemsSupplementBackButton = true;
NavigationItem.LeftBarButtonItem = leftMenuBarItem;
NavigationItem.RightBarButtonItem = rightMenuBarItem;
Thanks!
refer to UIBarButtonItem on iOS 11
UIBarButtonItem uses autolayout instead of dealing with frames.
That's why the button is got stretched .
Modify:
widthConstraint = leftBackBtn.WidthAnchor.ConstraintEqualTo(27);
heightConstraint = leftBackBtn.HeightAnchor.ConstraintEqualTo(20);
widthConstraint.Active = true;
heightConstraint.Active = true;

Xamarin.iOS: Try to move bottom toolbar(text field) above keyboard when editing like chat window

I tried to put the toolbar(with text field) above the keyboard. Initially, the toolbar was at the bottom.
I tried to use "inputAccessaryView" on the text field. The toolbar just disappear after I clicked inside the text field. I know this will work if I created a new toolbar for it. But like in the chat window, I want the same textfield/toolbar.
Here is the code
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
NavigationItem.Title = "Name";
ChatInput = new UITextField (new RectangleF(0,0,View.Bounds.Width - 104f,30f));
Toolbar = new UIToolbar (new RectangleF(0, View.Bounds.Height - 44.0f, View.Bounds.Width, 44f));
ChatInput.BorderStyle = UITextBorderStyle.RoundedRect;
Toolbar.SetItems( new UIBarButtonItem[] {
new UIBarButtonItem(UIBarButtonSystemItem.Refresh, (s,e) => {
Console.WriteLine("Refresh clicked");
})
, new UIBarButtonItem (ChatInput){Style = UIBarButtonItemStyle.Bordered,Width = View.Bounds.Width - 104f}
, new UIBarButtonItem(UIBarButtonSystemItem.Reply, (s,e) => {
Console.WriteLine ("Reply clicked");
})
}, false);
ChatInput.ReturnKeyType = UIReturnKeyType.Send;
ChatInput.ShouldBeginEditing = delegate {
ChatInput.InputAccessoryView = Toolbar;
return true;
};
ChatInput.ShouldReturn = delegate {
ChatInput.ResignFirstResponder();
return true;
};
View.AddSubview (Toolbar);
}
I don't know if there's a way to pin the toolbar on top of the keyboard, but what you could do it create some kind of method to move the toolbar (edit its .Frame property) when the keyboard pops up. I use this method to move an entire UIScrollView up. You can find the method I used here: (http://www.gooorack.com/2013/08/28/xamarin-moving-the-view-on-keyboard-show/).
This may not be the most "clean" solution, but if implemented correctly, it does its job. Another advantage is, is if you put the entire "moving of the keyboard" in a separate class-file, you can re-use it in other views.
Hope this helps. Good luck!
Love and regards,
Björn

Is there any custom date picker for iOS where year selection is optional?

I need to be able to select day and month and leave the option to the user to select the year or not. For example I was thinking a list with all the years and at the end an added option "no selection".
Any ideas how to do that?
I suppose that using the picker view is one solution but not sure.
Thanks
Using xamarin.ios what I did was create a toolbar on top of the thumbwheel with a Done and a Cancel buttons. When you click done the value is set, and you click cancel what you need to do is set the Datepicker value to a value like 1900-1-1 and change the uitextfield value to something like "Not set".
I'm using xamarin forms. This is what I have in my custom renderer:
public override void Draw (CGRect rect)
{
base.Draw (rect);
DatePicker elem = (DatePicker)Element;
UITextField textField = (UITextField)Control;
var toolbar = new UIToolbar(new CGRect(0.0f, 0.0f, Control.Frame.Size.Width, 44.0f));
toolbar.Items = new[]
{
new UIBarButtonItem(UIBarButtonSystemItem.Cancel,(object sender, EventArgs e) => {
if (elem.SetValueNullAction!=null){
elem.SetValueNullAction();
textField.Text = DefaultNotSetText;
}
}),
new UIBarButtonItem(UIBarButtonSystemItem.FlexibleSpace),
new UIBarButtonItem(UIBarButtonSystemItem.Done,(object sender, EventArgs e) => {
elem.Unfocus();
})
};
textField.InputAccessoryView = toolbar;
textField.BorderStyle = UITextBorderStyle.None;
textField.TextColor = Color.FromHex ("999999").ToUIColor ();
CGRect frame = textField.Frame;
frame.Width = 100;
textField.Frame = frame;
if (elem.Date == elem.MinimumDate) {
textField.Text = ((DatePicker)this.Element).Label;
}
}
Hope this helps!
You can have a try of CKPickerView, it allows very easy customization on UIDatePicker.

Xamarin FlyoutNavigationController does not show section FooterView

I want to implement a flyout navigation in Xamarin.iOS. For this purpose I am using the FlyoutNavigationController, which works good so far.
But now I have to display some additional content underneath the navigation list inside of the flyout-menu (basically an image, some labels and buttons). For this purpose, I wanted to use the FooterView property of the "section" control that holds the menu items.
When I set
section.Footer = "Test";
it will work (I can see the text), but when I use the 'FooterView' property, nothing shows up:
public class ViewController : UIViewController
{
FlyoutNavigationController navigation;
private const string PageNamePage1 = "The first page";
private const string PageNamePage2 = "The second page";
readonly string[] pages =
{
PageNamePage1,
PageNamePage2
};
public override void ViewDidLoad()
{
base.ViewDidLoad();
navigation = new FlyoutNavigationController
{
View =
{
Frame = UIScreen.MainScreen.Bounds
}
};
View.AddSubview(navigation.View);
var elements = pages.Select(page => new StringElement(page) as Element);
navigation.NavigationRoot = new RootElement("Induserv App");
var section = new Section();
section.AddAll(elements);
var uiTextView = new UITextView {Text = "--> This won't show!"};
section.FooterView = new UIView
{
uiTextView
};
navigation.NavigationRoot.Add(section);
navigation.ViewControllers = new UIViewController[]
{
new UINavigationController(new Page1Controller(navigation, PageNamePage1)),
new UINavigationController(new Page2Controller(navigation, PageNamePage2)),
};
}
}
Does anyone have an idea what it needs to display this footer here? Is there another way to put some controls in this panel?
Set a frame for both the footer view and uiTextView, like so:
var uiTextView = new UITextView(new RectangleF(0, 0, 10, 10)) {Text = "--> This won't show!"};
section.FooterView = new UIView(new RectangleF(0, 0, 10, 10))
{
uiTextView
};

Resources