Xamarin iOS UINavigationBar weird overlay - ios

I am working in Xamarin 4.5 with iOS 13. I am using Simulator to run the code. Here's how it looks.
I have added the following code to apply red color but its not hiding this white/grey overlay.
UIApplication.SharedApplication.StatusBarStyle = UIStatusBarStyle.LightContent;
UINavigationBar.Appearance.BarTintColor = UIColor.Red;
UINavigationBar.Appearance.TintColor = UIColor.Red;
UINavigationBar.Appearance.TitleTextAttributes = new UIStringAttributes
{
ForegroundColor = UIColor.Red
};
UINavigationBar.Appearance.BackgroundColor = UIColor.FromRGBA(255, 0, 0, 255);
Last line added the Red color.

It will be an expected effect because UINavigationBar has a default CALayer after iOS 11.0. As a workaround , we could create a custom NavigationBar by using custom renderer
in your iOS project
using Foundation;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
using xxx;
using xxx.iOS;
using CoreGraphics;
using ObjCRuntime;
[assembly:ExportRenderer(typeof(ContentPage),typeof(MyPageRenderer))]
namespace xxx.iOS
{
public class MyPageRenderer:PageRenderer
{
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
NavigationController.NavigationBar.Hidden = true;
double height = IsiphoneX();
UIView backView = new UIView()
{
BackgroundColor = UIColor.Red,
Frame = new CGRect(0, 20, UIScreen.MainScreen.Bounds.Width, height),
};
// set
UIButton backBtn = new UIButton()
{
Frame = new CGRect(20, height - 44, 40, 44),
Font = UIFont.SystemFontOfSize(18),
};
backBtn.SetTitle("<",UIControlState.Normal);
backBtn.SetTitleColor(UIColor.White,UIControlState.Normal);
backBtn.AddTarget(this, new Selector("GoBack"), UIControlEvent.TouchUpInside);
UILabel titleLabel = new UILabel()
{
Frame = new CGRect(UIScreen.MainScreen.Bounds.Width / 2 - 75, 0, 150, height),
Font = UIFont.SystemFontOfSize(20),
Text = "xxx",
TextColor = UIColor.White,
Lines = 0,
};
UILabel line = new UILabel()
{
Frame = new CGRect(0, height, UIScreen.MainScreen.Bounds.Width, 0.5),
BackgroundColor = UIColor.Black,
};
if (NavigationController.ViewControllers.Length > 1)
{
backView.AddSubview(backBtn);
}
backView.AddSubview(titleLabel);
backView.AddSubview(line);
View.AddSubview(backView);
}
double IsiphoneX()
{
double height = 44;
if (UIDevice.CurrentDevice.CheckSystemVersion(11, 0))
{
if (UIApplication.SharedApplication.Delegate.GetWindow().SafeAreaInsets.Bottom > 0.0)
{
height = 64;
}
}
return height;
}
[Export("GoBack")]
void GoBack()
{
NavigationController.PopViewController(true);
}
public override void ViewWillDisappear(bool animated)
{
base.ViewWillDisappear(animated);
NavigationController.NavigationBar.Hidden = false;
}
}
}
You can set the property of title , backButton and navigationBar as you need (such as text , color ,BackgroundColor ,font e.g.)

Related

Setting the font on navigation bar buttons in a Xamarin Forms iOS 13+ app

I'm trying to set the font for navigation buttons (specifically the Back button) in Xamarin iOS (13+) apps. I found this this solution which claims to work but didn't, for me at least:
var style = new UINavigationBarAppearance();
var a = new UIStringAttributes();
a.Font = UIFont.SystemFontOfSize(35);
a.ForegroundColor = UIColor.Yellow;
style.TitleTextAttributes = a;
var dic = new NSDictionary<NSString, NSObject>(
new NSString[] {a.Dictionary.Keys[0] as NSString, a.Dictionary.Keys[1] as NSString }, a.Dictionary.Values
);
var button = new UIBarButtonItemAppearance(UIBarButtonItemStyle.Plain);
button.Normal.TitleTextAttributes = dic;
button.Highlighted.TitleTextAttributes = dic;
style.ButtonAppearance = button;
UINavigationBar.Appearance.StandardAppearance = style;
I then simplified it a little (seeing if I could simply recolour the nav bar title) but this again did nothing:
var style = new UINavigationBarAppearance();
var a = new UIStringAttributes()
{
ForegroundColor = UIColor.Yellow
};
style.TitleTextAttributes = a;
UINavigationBar.Appearance.StandardAppearance = style;
Playing around further I found, curiously, the following DOES recolour the navigation bar title:
var a = new UIStringAttributes()
{
ForegroundColor = UIColor.Yellow
};
UINavigationBar.Appearance.TitleTextAttributes = a;
...but using the same thought process, this does NOT recolour the navigation bar buttons:
var a = new UITextAttributes()
{
TextColor = UIColor.Yellow
};
UIBarButtonItem.Appearance.SetTitleTextAttributes(a, UIControlState.Normal);
Can anyone see why none of these approaches work for modifying the navigation bar button styling? Or might this be an issue with Xamarin?
UPDATE: I realised the first sample does work, but only in Xamarin iOS. It does not work in Xamarin Forms however. It looks like Xamarin Forms might be enforcing its own standard appearance which overrides what I put in my code.
In your case we could set a custom NavigationBar .
In your ViewController
If you want to let it works on all Controllers , you could define a base ViewController
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
var page = Element as ContentPage;
NavigationController.NavigationBar.Hidden = true;
double height = IsiphoneX();
UIView backView = new UIView()
{
BackgroundColor = UIColor.White,
Frame = new CGRect(0,20,UIScreen.MainScreen.Bounds.Width, height),
};
UIButton backBtn = new UIButton() {
Frame = new CGRect(20, height-44, 40, 44),
Font = UIFont.SystemFontOfSize(18), // set style here
} ;
backBtn.SetTitle("Back", UIControlState.Normal);
backBtn.SetTitleColor(UIColor.Blue, UIControlState.Normal);
backBtn.AddTarget(this,new Selector("GoBack"),UIControlEvent.TouchUpInside);
UILabel titleLabel = new UILabel() {
Frame=new CGRect(UIScreen.MainScreen.Bounds.Width/2-75, 0,150, height),
Font = UIFont.SystemFontOfSize(20),
Text = page.Title,
TextColor = UIColor.Black,
Lines = 0,
};
UILabel line = new UILabel() {
Frame = new CGRect(0, height, UIScreen.MainScreen.Bounds.Width, 0.5),
BackgroundColor = UIColor.Black,
};
backView.AddSubview(backBtn);
backView.AddSubview(titleLabel);
backView.AddSubview(line);
View.AddSubview(backView);
}
double IsiphoneX()
{
double height = 44; //set height as you want here !!!
if (UIDevice.CurrentDevice.CheckSystemVersion(11, 0))
{
if (UIApplication.SharedApplication.Delegate.GetWindow().SafeAreaInsets.Bottom > 0.0)
{
height = 64; //set height as you want here !!!
}
}
return height;
}
[Export("GoBack")]
void GoBack()
{
NavigationController.PopViewController(true);
}
public override void ViewWillDisappear(bool animated)
{
base.ViewWillDisappear(animated);
NavigationController.NavigationBar.Hidden = false;
}
In this way you could set all style as you want like BackgroundColor , TextColor or even set the back button as an image .
I finally figured out an approach that works by overriding Xamarin Forms' constant enforcement of its own navigation bar styling:
public class MyNavigationRenderer : NavigationRenderer
{
public override void ViewDidAppear(bool animated)
{
base.ViewDidAppear(animated);
UpdateStyle();
Element.PropertyChanged += HandlePropertyChanged;
}
void UpdateStyle()
{
var navigationBarAppearance = NavigationBar.StandardAppearance;
var titleTextAttributes = new UIStringAttributes
{
ForegroundColor = UIColor.Yellow,
Font = UIFont.SystemFontOfSize(35)
};
var dic = new NSDictionary<NSString, NSObject>(
new NSString[] { titleTextAttributes.Dictionary.Keys[0] as NSString, titleTextAttributes.Dictionary.Keys[1] as NSString }, titleTextAttributes.Dictionary.Values
);
var button = new UIBarButtonItemAppearance(UIBarButtonItemStyle.Plain);
button.Normal.TitleTextAttributes = dic;
button.Highlighted.TitleTextAttributes = dic;
navigationBarAppearance.ButtonAppearance = button;
NavigationBar.StandardAppearance = navigationBarAppearance;
NavigationBar.CompactAppearance = navigationBarAppearance;
NavigationBar.ScrollEdgeAppearance = navigationBarAppearance;
}
void HandlePropertyChanged(object sender, PropertyChangedEventArgs e)
{
UpdateStyle();
}
}

Overriding Back button navigation in Xamarin.IOS

I am trying to override the default back button behaviour of IOS, using Xamarin.IOS framework.
I have a stack of objects inside my ViewController, my requirement is that when the user presses back to navigate to previous ViewController, i will navigate only when my stack is empty otherwise i will stay in that screen(ViewController).
For this i tried several thing, like overriding the ViewWillDisappear and setting the PopViewController to false but i am unable to do this. Please guide.
public override void ViewWillDisappear(bool animated)
{
Stack<Object> st = vPage.uContentStack;
if (st.Count != 0)
{
Object pop_obj = st.Pop();
if (st.Count != 0)
{
NavigationController.PopViewController(false);// Here trying to stop navigating back
Object peek_obj = st.Peek();
vPage.ContentUpdateOnBackPress(pop_obj, peek_obj);
}
else
{
NavigationController.PopViewController(true);
}
}
else
{
NavigationController.PopViewController(true);
}
base.ViewWillDisappear(animated);
}
You could customize the Navigation Bar in the specific ViewController
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
NavigationController.NavigationBar.Hidden = true;
double height = IsiphoneX();
UIView backView = new UIView()
{
BackgroundColor = UIColor.White,
Frame = new CGRect(0, 20, UIScreen.MainScreen.Bounds.Width, height),
};
UIButton backBtn = new UIButton()
{
Frame = new CGRect(20, height - 44, 40, 44),
Font = UIFont.SystemFontOfSize(18),
};
backBtn.SetTitle("<", UIControlState.Normal);
// backBtn.SetBackgroundImage(UIImage.FromBundle("xx.png"),UIControlState.Normal); or you can set image here
backBtn.SetTitleColor(UIColor.FromRGB(60,140,250), UIControlState.Normal);
backBtn.AddTarget(this, new Selector("GoBack"), UIControlEvent.TouchUpInside);
UILabel titleLabel = new UILabel()
{
Frame = new CGRect(UIScreen.MainScreen.Bounds.Width / 2 - 75, 0, 150, height),
Font = UIFont.SystemFontOfSize(20),
Text = "xxx",
TextAlignment = UITextAlignment.Center,
TextColor = UIColor.Black,
Lines = 0,
};
UILabel line = new UILabel()
{
Frame = new CGRect(0, height, UIScreen.MainScreen.Bounds.Width, 0.5),
BackgroundColor = UIColor.Black,
};
backView.AddSubview(backBtn);
backView.AddSubview(titleLabel);
backView.AddSubview(line);
View.AddSubview(backView);
}
double IsiphoneX()
{
double height = 44;
if (UIDevice.CurrentDevice.CheckSystemVersion(11, 0))
{
if (UIApplication.SharedApplication.Delegate.GetWindow().SafeAreaInsets.Bottom > 0.0)
{
height = 64;
}
}
return height;
}
[Export("GoBack")]
void GoBack()
{
//handle logic here
}
public override void ViewWillDisappear(bool animated)
{
base.ViewWillDisappear(animated);
NavigationController.NavigationBar.Hidden = false;
}
In this solution you could set the style of the navigation bar , like text color of title or icon of back button .

Xamarin iOS adding Custom back button

I want to customise back-button so i can prompt user with confirmation box.
For that i have removed default navigation back button by setting its hidden property to 'True'
and i am adding new left bar button item.
But UI for the left bar button is not same as it is for default back button.
please find attached screenshot.
Please find below code for Left bar button added-
UIImage image = UIImage.FromBundle("BackButton"); UIButton customButton = new UIButton(UIButtonType.Custom);
customButton.SetImage(image.ImageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate),
UIControlState.Normal); customButton.Frame = new CGRect(0, 0,
100, 44); customButton.ImageEdgeInsets = new UIEdgeInsets(0,
-40, 0, -40); this.NavigationItem.SetHidesBackButton(true, false); var backButton = new
UIBarButtonItem(customButton);
this.NavigationItem.LeftBarButtonItem = backButton;
Thanks in advance !
You would better scale the image before you set the background image.
UIImage image = UIImage.FromBundle("BackButton").ImageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal);
UIImage newImg = ScalingImageToSize(image, new CGSize(30, 30)).ImageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal);
UIButton customButton = new UIButton(UIButtonType.Custom);
customButton.SetImage(newImg.ImageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal), UIControlState.Normal);
customButton.Frame = new CGRect(0, 0, 50, 50);
customButton.ImageEdgeInsets = new UIEdgeInsets(0, -40, 0, -40);
NavigationController.NavigationBar.BackIndicatorImage = newImg;
NavigationController.NavigationBar.BackIndicatorTransitionMaskImage = newImg;
UIBarButtonItem buttonItem = new UIBarButtonItem(customButton);
NavigationItem.BackBarButtonItem = buttonItem;
public UIImage ScalingImageToSize(UIImage sourceImage, CGSize newSize)
{
if (UIScreen.MainScreen.Scale == 2.0) //#2x iPhone 6 7 8
{
UIGraphics.BeginImageContextWithOptions(newSize, false, 2.0f);
}
else if (UIScreen.MainScreen.Scale == 3.0) //#3x iPhone 6p 7p 8p...
{
UIGraphics.BeginImageContextWithOptions(newSize, false, 3.0f);
}
else
{
UIGraphics.BeginImageContext(newSize);
}
sourceImage.Draw(new CGRect(0, 0, newSize.Width, newSize.Height));
UIImage newImage = UIGraphics.GetImageFromCurrentImageContext();
UIGraphics.EndImageContext();
return newImage;
}
Option 2
You can create a custom navigationBar as you want .
public class xxxViewController: UIViewController
{
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
NavigationController.NavigationBar.Hidden = true;
double height = IsiphoneX();
UIView backView = new UIView()
{
BackgroundColor = UIColor.White,
Frame = new CGRect(0,20,UIScreen.MainScreen.Bounds.Width, height),
};
// set
UIButton backBtn = new UIButton() {
Frame = new CGRect(20, height-44, 40, 44),
Font = UIFont.SystemFontOfSize(18),
} ;
UIImage image = UIImage.FromBundle("BackButton");
UIImage newImg = ScalingImageToSize(image, new CGSize(30, 30));
backBtn.SetBackgroundImage(newImg.ImageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate), UIControlState.Normal);
backBtn.AddTarget(this,new Selector("GoBack"),UIControlEvent.TouchUpInside);
UILabel titleLabel = new UILabel() {
Frame=new CGRect(UIScreen.MainScreen.Bounds.Width/2-75, 0,150, height),
Font = UIFont.SystemFontOfSize(20),
Text = "xxx",
TextColor = UIColor.Black,
Lines = 0,
};
UILabel line = new UILabel() {
Frame = new CGRect(0, height, UIScreen.MainScreen.Bounds.Width, 0.5),
BackgroundColor = UIColor.Black,
};
backView.AddSubview(backBtn);
backView.AddSubview(titleLabel);
backView.AddSubview(line);
View.AddSubview(backView);
}
double IsiphoneX()
{
double height = 44;
if (UIDevice.CurrentDevice.CheckSystemVersion(11, 0))
{
if (UIApplication.SharedApplication.Delegate.GetWindow().SafeAreaInsets.Bottom > 0.0)
{
height = 64;
}
}
return height;
}
[Export("GoBack")]
void GoBack()
{
NavigationController.PopViewController(true);
}
public override void ViewWillDisappear(bool animated)
{
base.ViewWillDisappear(animated);
NavigationController.NavigationBar.Hidden = false;
}
}
You can set the property of title , backButton and navigationBar as you need (such as text , color ,BackgroundColor ,font e.g.)

resize cell in xamarin

I have a table view built in Xamarin that is populated with some addresses, but i can't figure out how to resize the cell so that all information will fit.
My TableViewCell Class:
using System;
using MonoTouch.Foundation;
using MonoTouch.UIKit;
using System.CodeDom.Compiler;
using System.Drawing;
namespace Vipar
{
public class CustomVegeeeCell : UITableViewCell {
UILabel Title, Addr, CityState;
//UIImageView imageView;
public CustomVegeeeCell (NSString cellId) : base (UITableViewCellStyle.Default, cellId)
{
SelectionStyle = UITableViewCellSelectionStyle.Gray;
ContentView.BackgroundColor = UIColor.Clear;//(84, 84, 85);
//imageView = new UIImageView();
Title = new UILabel () {
Font = UIFont.FromName("Arial-BoldMT", 16f),
TextColor = UIColor.Black,
BackgroundColor = UIColor.Clear
};
Addr = new UILabel () {
Font = UIFont.FromName("ArialMT", 12f),
TextColor = UIColor.Black,
//TextAlignment = UITextAlignment.Center,
BackgroundColor = UIColor.Clear
};
CityState = new UILabel () {
Font = UIFont.FromName("ArialMT", 12f),
TextColor = UIColor.Black,
//TextAlignment = UITextAlignment.Center,
BackgroundColor = UIColor.Clear
};
ContentView.Add (Title);
ContentView.Add (Addr);
ContentView.Add (CityState);
}
public void UpdateCell (string caption, string subtitle, string subtitle1)//, UIImage image)
{
//imageView.Image = image;
Title.Text = caption;
Addr.Text = subtitle;
CityState.Text = subtitle1;
}
public override void LayoutSubviews ()
{
base.LayoutSubviews ();
//imageView.Frame = new RectangleF(ContentView.Bounds.Width - 63, 5, 33, 33);
Title.Frame = new RectangleF(5, 4, ContentView.Bounds.Width - 63, 25);
Addr.Frame = new RectangleF(5, 18, ContentView.Bounds.Width - 63, 25);
CityState.Frame = new RectangleF(5, 30, ContentView.Bounds.Width - 63, 25);
}
}
}
In UITableViewSource, you need to override GetHeightForRow:
public override float GetHeightForRow(UITableView tableView, NSIndexPath indexPath)

How to change SeparatorColor of Selected Item in a UITableView

I've got the following UITableView
_navigationList = new UITableView
{
Source = UINavigationTableViewSource,
BackgroundColor = UIColor.FromRGB(43, 43, 43), // #2b2b2b - same as Android
SeparatorColor = UIColor.FromRGB(27,27,27), // #1b1b1b - same as Android
SeparatorInset = UIEdgeInsets.Zero,
ScrollEnabled = true
};
The UINavigationTableViewSource is using a custom UITableViewCell
public sealed class UINavigationTableViewCell : UITableViewCell
{
public new readonly UILabel TextLabel;
public UINavigationTableViewCell(string cellId)
: base(UITableViewCellStyle.Default, cellId)
{
TextLabel = new UILabel(new RectangleF(10, 0, Bounds.Width, 40)) {TextColor = UIColor.White}; // properly position the label.
SeparatorInset = UIEdgeInsets.Zero; // make the boarder go all the way across the list item
ContentView.BackgroundColor = UIColor.FromRGB(43, 43, 43); // #2b2b2b - same as Android
var activeOrb = new UIImageView(new RectangleF(0,0,10,Bounds.Height))
{
Image = UIImage.FromBundle("Images/active_orb.png"),
ContentMode = UIViewContentMode.ScaleAspectFit
};
SelectedBackgroundView = new UIView { BackgroundColor = UIColor.FromRGB(43, 43, 43) };
SelectedBackgroundView.Add(activeOrb);
ContentView.Add(TextLabel);
}
}
Everything is looking the way we want except for the ugly white line on a selected row.
How do I change the SeparatorColor when a row is selected?
I had never programmed in xamarin, but i worked on ios(5-7) sdk.
I would suggest you to dont use any seperators.Instead add the seperator line as view(height-1pixel;width-cellWidth) to your cell.
edit by ChaseFlorell - working example
_navigationList = new UITableView
{
Source = UINavigationTableViewSource,
BackgroundColor = UIColor.FromRGB(43, 43, 43), // #2b2b2b - same as Android
SeparatorStyle = UITableViewCellSeparatorStyle.None,
ScrollEnabled = true
};
Add(_navigationList);
public sealed class UINavigationTableViewCell : UITableViewCell
{
public new readonly UILabel TextLabel;
public UINavigationTableViewCell(string cellId) : base(UITableViewCellStyle.Default, cellId)
{
// The default state
TextLabel = new UILabel(new RectangleF(10, 0, Bounds.Width, 40)) { TextColor = UIColor.White }; // properly position the label.
ContentView.BackgroundColor = UIColor.FromRGB(43, 43, 43); // #2b2b2b - same as Android
ContentView.Add(Separator(Bounds));
ContentView.Add(TextLabel);
// todo: move colors to a config file.
// The selected state
var activeOrb = new UIImageView(new RectangleF(0, 0, 10, Bounds.Height))
{
Image = UIImage.FromBundle("Images/active_orb.png"),
ContentMode = UIViewContentMode.ScaleAspectFit
};
SelectedBackgroundView = new UIView { BackgroundColor = UIColor.FromRGB(43, 43, 43) };
SelectedBackgroundView.Add(Separator(Bounds));
SelectedBackgroundView.Add(activeOrb);
}
private static UIView Separator(RectangleF bounds)
{
return new UIView(new RectangleF(0, 0, bounds.Width, 1))
{
BackgroundColor = UIColor.FromRGB(27, 27, 27)
};
}
}

Resources