iOS 11 navigation bar / uibarbutton items rendering issues - ios

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;

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:).

Popup picker in Xamarin 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;

Adding Tag View to Xamarin iOS Application

How to have a tag bubbles like in the attached image.I have done this for android using TagView component but not sure how to do it for Xamarin iOS?Any component that I can refer?
You will have to write this custom component yourself .
I would recommend having this designed in XIB/Storyboard and place em at runtime .
very rough idea to create one such subview programmitically could be something like
var myView = new UIView(frame: new CoreGraphics.CGRect(10, 10, 120, 40));
myView.BackgroundColor = UIColor.Blue;
myView.Layer.CornerRadius = 20;
var mylabel = new UILabel(frame: new CoreGraphics.CGRect(10, 10, 80, 40));
mylabel.Text = "MUMBAI";
myView.Add(mylabel);
UIButton button = new UIButton();
button.Frame = new CoreGraphics.CGRect(mylabel.Frame.X + mylabel.Frame.Width, 10f, 40, 25);
button.SetTitle("Title", UIControlState.Normal);
button.SetBackgroundImage(UIImage.FromBundle("MyImage"),UIControlState.Normal);
myView.Add(button);
View.Add(myView);
Here frame calculation you need to do ,above are just some sample frame I put .
so ultimately you gonna make such views stack em horizontally ,and when user clicks "x" button , you change the frame with animation .
Try this
https://github.com/nmilcoff/TagsView
It's super simple to get started:
public class ViewController : UIViewController
{
private TagListView tagsView;
public override void ViewDidLoad()
{
// code
this.tagsView = new TagListView()
{
// you can customize properties here!
};
this.View.AddSubview(this.tagsView);
this.View.AddConstraints(
// Add your constraints!
);
// you can attach a source object to each tag
var myObject = new MyModel { Title = "I'm a MyModel!" };
this.tagsView.AddTag(myObject.Title, myObject);
// but, if none is provided, it will be the text string
this.tagsView.AddTag("I'm a simple tag!");
}
}

How to set LeftBarButton at the place of BackButton in ios

I have set LeftBarButton in the NavigationItem is below way.
Code :
UIButton leftBtn = new UIButton();
leftBtn.Frame = new CoreGraphics.CGRect(0, 14, 30, 30);
leftBtn.SetImage(UIImage.FromBundle("cancel_white_icon"), UIControlState.Normal);
leftBtn.TintColor = GargiColor.WhiteColor();
UIBarButtonItem barBtnLeft = new UIBarButtonItem();
barBtnLeft.CustomView = leftBtn;
barBtnLeft.TintColor = GargiColor.WhiteColor();
NavigationItem.SetLeftBarButtonItem(barBtnLeft, true);
Output :
EDIT :
After adding #SushiHangover code the Output is below
What I am Expected :
The Cancel Button have more space in the Left Side. How to set it to LeftSide as the backbutton.
My Require Output is below :
#SushiHangover final output :
var negativeSpace = new UIBarButtonItem (UIBarButtonSystemItem.FixedSpace);
negativeSpacae.Width = -8;
var leftBtn = new UIButton (new RectangleF (0, 0, 25, 25));
leftBtn.SetImage(UIImage.FromBundle("cancel_white_icon"), UIControlState.Normal);
leftBtn.TintColor = GargiColor.WhiteColor();
UIBarButtonItem [] bArray = {
negativeSpace, new UIBarButtonItem (leftBtn)
};
NavigationItem.SetLeftBarButtonItems (bArray, true);

IOS: UIDatePicker renders poorly with a black background

When I create a new UIDatePicker with its Mode set to a CountDownTimer, it renders poorly with a black background. Anyone have any insight?
Normal Picker looks like this:
CODE: Note the UIButton is a full screen button behind the picker to dismiss the view
intervalPicker = new UIDatePicker(new RectangleF(0, this.tvc.View.Bounds.Height - 135, this.tvc.View.Bounds.Width, 200));
intervalPicker.Mode = UIDatePickerMode.CountDownTimer;
intervalPicker.CountDownDuration = DeviceSession.CurrentBehavioralEvent.Duration*60;
intervalPicker.ValueChanged += new EventHandler(intervalPicker_EditingChanged);
UIButton b = UIButton.FromType(UIButtonType.Custom);
b.Opaque = false;
b.BackgroundColor = UIColor.Clear;
b.Frame = new RectangleF(0, 0, this.tvc.View.Bounds.Width, this.tvc.View.Bounds.Height);
b.TouchUpInside += (o, s) => {
intervalPicker.RemoveFromSuperview();
b.RemoveFromSuperview();
};
this.tvc.NavigationController.View.AddSubview(b);
this.tvc.NavigationController.View.AddSubview(intervalPicker);
The UIDatePicker in CountDownTimer mode displays this way when you set a frame height of less than 216. The other modes don't have this problem.
Your example is setting the height to 200.
Change the height to 216.

Resources