Change status bar colour on iOS13 - c#

Before iOS 13 I could change the status bar colour using the following bit of code:
UIView statusBar = UIApplication.SharedApplication.ValueForKey(new NSString("statusBar")) as UIView;
if (statusBar.RespondsToSelector(new ObjCRuntime.Selector("setBackgroundColor:")))
{
statusBar.BackgroundColor = UIColor.Clear.FromHex(0x323232);
statusBar.TintColor = UIColor.White;
app.StatusBarStyle = UIStatusBarStyle.BlackOpaque;
}
However, on iOS13 I get the following runtime error
Objective-C exception thrown. Name: NSInternalInconsistencyException Reason: App called -statusBar or -statusBarWindow on UIApplication: this code must be changed as there's no longer a status bar or status bar window. Use the statusBarManager object on the window scene instead.
Any idea on how to change the status bar on iOS13?
EDIT: Just to point out, this is for Xamarin and not for Swift. To clarify the duplicate marker.

From error , you need to use UIStatusBarManager in IOS 13.
If you have updated VS to the latest version(Visual Studio 2019 version 16.3.0/Visual Studio 2019 for Mac version 8.3 above), you can change color as follow:
UIView statusBar = new UIView(UIApplication.SharedApplication.KeyWindow.WindowScene.StatusBarManager.StatusBarFrame);
statusBar.BackgroundColor = UIColor.Yellow;
UIApplication.SharedApplication.KeyWindow.AddSubview(statusBar);
Else the follow methods can make it works .
UIView statusBar = new UIView(UIApplication.SharedApplication.StatusBarFrame);
statusBar.BackgroundColor = UIColor.Yellow;
UIApplication.SharedApplication.KeyWindow.AddSubview(statusBar);
If the view is not fully rendered , UIApplication.SharedApplication.KeyWindow will return null .So you can change status bar color after fully rendered . Here is the sample .
===================================Update=================================
If in Forms project , you can have a try with invoking method in AppDelegate.cs
public override void OnActivated(UIApplication uiApplication)
{
if (UIDevice.CurrentDevice.CheckSystemVersion(13, 0))
{
// If VS has updated to the latest version , you can use StatusBarManager , else use the first line code
// UIView statusBar = new UIView(UIApplication.SharedApplication.StatusBarFrame);
UIView statusBar = new UIView(UIApplication.SharedApplication.KeyWindow.WindowScene.StatusBarManager.StatusBarFrame);
statusBar.BackgroundColor = UIColor.Red;
UIApplication.SharedApplication.KeyWindow.AddSubview(statusBar);
}
else
{
UIView statusBar = UIApplication.SharedApplication.ValueForKey(new NSString("statusBar")) as UIView;
if (statusBar.RespondsToSelector(new ObjCRuntime.Selector("setBackgroundColor:")))
{
statusBar.BackgroundColor = UIColor.Red;
UIApplication.SharedApplication.StatusBarStyle = UIStatusBarStyle.BlackOpaque;
}
}
base.OnActivated(uiApplication);
}
Note :
Not sure this solurion will always work in AppDelegate.cs, better invoked in Controller.cs's method , because from iOS 13 , Apple have modified the architure of AppDelegate and added SceneDelegate to project.

This also works, if used in ViewDidAppear override in a UIViewController. I previously tested in ViewWillAppear and even that was too soon to have a KeyWindow non-null:
public override void ViewDidAppear(bool animated)
{
base.ViewDidAppear(animated);
if (UIDevice.CurrentDevice.CheckSystemVersion(13, 0))
{
//Obj-C:
// UIView *statusBar = [[UIView alloc]initWithFrame:[UIApplication sharedApplication].keyWindow.windowScene.statusBarManager.statusBarFrame] ;
// statusBar.backgroundColor = [UIColor redColor];
// [[UIApplication sharedApplication].keyWindow addSubview:statusBar];
// Xamarin.iOS:
UIView statusBar = new UIView(UIApplication.SharedApplication.KeyWindow.WindowScene.StatusBarManager.StatusBarFrame);
statusBar.BackgroundColor = UIColor.Red;
UIApplication.SharedApplication.KeyWindow.AddSubview(statusBar);
}
else
{
UIView statusBar = UIApplication.SharedApplication.ValueForKey(new NSString("statusBar")) as UIView;
if (statusBar.RespondsToSelector(new ObjCRuntime.Selector("setBackgroundColor:")))
{
statusBar.BackgroundColor = UIColor.Red;
statusBar.TintColor = UIColor.White;
UIApplication.SharedApplication.StatusBarStyle = UIStatusBarStyle.BlackOpaque;
}
}
}
And that is the same solution provided in the duplicate question: https://stackoverflow.com/a/58028658/2913599

Could you please try the below solution. it works fine for me in the same scenario
if (#available(iOS 13.0, *)) {
UIView *statusBar = [[UIView alloc]initWithFrame:[UIApplication sharedApplication].keyWindow.windowScene.statusBarManager.statusBarFrame];
statusBar.backgroundColor = [UIColor redColor];
[[UIApplication sharedApplication].keyWindow addSubview:statusBar];
} else {
// Fallback on earlier versions
UIView *statusBar=[[UIApplication sharedApplication] valueForKey:#"statusBar"];
statusBar.backgroundColor = [UIColor redColor];
[statusBar setNeedsDisplay];
}

Related

Xamarin Forms iOS RootViewController.View.AddSubview() not showing element in a page with Shell.PresentationMode="ModalAnimated"

I'm trying to add a floating Button for all my screens in a Xamarin forms app using Dependency service for each platform. iOS is working fine with any ContentPage but it fails when I set Shell.PresentationMode="ModalAnimated", button is not showing or is printing behind of ContentPage with animated modal.
Calling dependency service in my all views in Xamarin Forms
DependencyService.Get<IDeviceService>().ShowFloatingButton();
Dependency service implementation for iOS
namespace WebviewSample.iOS.DependencySeivices
{
public class DeviceService : IDeviceService
{
private void ShowFloatingButton()
{
var vc = UIApplication.SharedApplication.KeyWindow.RootViewController;
var btn = UIButton.FromType(UIButtonType.System);
btn.Frame = new CGRect(20, 200, 280, 44);
btn.SetTitle("Click Me", UIControlState.Normal);
vc.View.BackgroundColor = UIColor.DarkGray;
vc.View.AddSubview(btn);
vc.View.BringSubviewToFront(btn);
}
}
}
I have tried to get the top controller as below samples:
if (UIApplication.SharedApplication.KeyWindow.WindowLevel != UIWindowLevel.Normal)
{
foreach (var item in UIApplication.SharedApplication.Windows)
{
if (item.WindowLevel == UIWindowLevel.Normal)
{
vc = item.RootViewController;
break;
}
}
}
Also
while (vc.PresentedViewController != null)
{
vc = vc.PresentedViewController;
}
According to this document:https://devblogs.microsoft.com/xamarin/xamarin-forms-shell-quick-tip-modal-navigation/
Xamarin shell navigation is different than traditional navigation where a page is pushed onto the stack so a new page pops up over the current page.

iOS ScrollView w/contentView (UIView) doesn't display content (using Cirrious FluentLayouts)

I'm not very familiar with scroll views on iOS so please bear with me. I'm using Visual Studio 2019 Preview. I have a view on the main storyboard that has a banner at the top and a label under that. I then put a scroll view under the label as I do not want the banner and label to scroll off the screen. Then programmatically I add a UIView called contentView to the scroll view after adding two controls to the content view, a label called lblUsername and a text view called txtUsername, I set the text of the label to "Enter Username". I only added these two things to the content view to keep things simple until I could better understand how this all works. The code compiles with no errors, but when I run it on my test device, nothing appears other than the banner and the label I placed under that. My code:
public partial class createAccount : UIViewController
{
public User MyUser;
public createAccount (IntPtr handle) : base (handle)
{
}
public override void ViewDidLoad()
{
viewCreateAccount.SubviewsDoNotTranslateAutoresizingMaskIntoConstraints();
var height = this.NavigationController.NavigationBar.Bounds.Height;
UIView contentView = new UIView();
UILabel lblUsername = new UILabel();
UITextView txtUsername = new UITextView();
lblUsername.Text = "Enter Username: ";
contentView.AddSubviews(lblUsername);
contentView.AddSubviews(txtUsername);
viewCreateAccount.AddConstraints
(
banner.AtTopOf(View, height),
banner.AtRightOf(View, 0),
banner.AtLeftOf(View, 0),
lblTitle.Below(banner, 0),
lblTitle.WithSameWidth(banner)
);
scrollView.Add(contentView);
scrollView.SubviewsDoNotTranslateAutoresizingMaskIntoConstraints();
scrollView.AddConstraints(contentView.FullWidthOf(scrollView));
contentView.SubviewsDoNotTranslateAutoresizingMaskIntoConstraints();
contentView.AddConstraints(
lblUsername.AtTopOf(contentView,0),
lblUsername.AtLeftOf(contentView,0),
txtUsername.ToRightOf(lblUsername,2)
);
}
}
What am I missing??
I have tested in Version 16.6.1 of VS , it seems that UITextView can not shows when using Cirrious.FluentLayout .Maybe it's an issue or limitation of Cirrious.FluentLayout , you can connect to author to reprot this .
If modify the UITextView to UITextField , then it will show .
...
UIView contentView = new UIView();
UILabel lblUsername = new UILabel();
UITextField txtUsername = new UITextField();
lblUsername.Text = "Enter Username: ";
contentView.AddSubviews(lblUsername);
contentView.AddSubviews(txtUsername);
txtUsername.Text = "Enter UITextField ";
txtUsername.TextColor = UIColor.Black;
txtUsername.BackgroundColor = UIColor.Yellow;
...
The effect (here add a background color for scollview):

How to remove volume HUD on Xamarin Forms?

I have made a customrenderer to render a MPVolumeView inside of a xamarin.forms app. Whenever I adjust the volume, I get this big system HUD on screen that is blocking the content on screen. Looks something like this:
How do I remove this? This is my custom renderer:
public class AudioOutputViewRenderer : ViewRenderer<AudioOutputView, UIView>
{
MPVolumeView view;
protected override void OnElementChanged(ElementChangedEventArgs<AudioOutputView> e)
{
base.OnElementChanged(e);
TintColor = UIColor.FromRGB(54, 66, 94);
if (Control == null)
{
view = new MPVolumeView()
{
ShowsRouteButton = false,
ShowsVolumeSlider = true
};
SetNativeControl(view);
}
}
}
I didnt understand perpose of the AudioOutputViewRenderer
But to hide the MPVolumeView you need next:
in your IosProject -> AppDelegate -> method FinishedLaunching add next code
var volumeView = new MPVolumeView(new CGRect(-1000,0,0,0));// -1000 will hide your view from user
volumeView.ClipsToBounds = true;
var slider = volumeView.Subviews.First(x => x is UISlider) as UISlider;
UIApplication.SharedApplication.KeyWindow.RootViewController.View.AddSubview(volumeView);
After you can use var slider to change volume like this
slider.Value = [your vlm];

Closing Xamarin forms Navigation Drawer

I just started with Xamarin forms and followed this example. But for the landscape mode it always has Navigation drawer opened. Is this default behavior? Below is my code
public class NavigationDrawer : MasterDetailPage // Navigation Drawer using MasterDetailPage
{
public override bool ShouldShowToolbarButton()
{
return true;
}
ContentPage gotoPage;
public NavigationDrawer()
{
Title = "Navigation Drawer Using MasterDetailPage";
string[] myPageNames = { "Camera2 Demo", "Second", "Third" };
SizeChanged += NavigationDrawer_SizeChanged;
ListView listView = new ListView
{
ItemsSource = myPageNames,
};
this.Master = new ContentPage
{
Title = "Options",
Content = listView,
Icon = "hamburger.png"
};
listView.ItemTapped += (sender, e) =>
{
switch (e.Item.ToString())
{
case "Camera2 Demo":
gotoPage = new CameraPage();
break;
case "Second":
gotoPage = new SecondPage();
break;
case "Third":
gotoPage = new ThirdPage();
break;
default:
gotoPage = new NavigationPage1();
break;
}
Detail = new NavigationPage(gotoPage);
((ListView)sender).SelectedItem = null;
this.IsPresented = true;
};
Detail = new NavigationPage(new HomePage());
IsPresented = false;
//// For Windows Phone, provide a way to get back to the master page.
//if (Device.OS == TargetPlatform.WinPhone)
//{
// (this.Detail as ContentPage).Content.GestureRecognizers.Add(
// new TapGestureRecognizer((view) =>
// {
// this.IsPresented = true;
// }));
//}
}
Question
1) How would I control opening and closing of Navigation Drawer? I found a way where it would give us control over the width of the navigation Drawer. Here is the Link. But is this the best option available right now?
1) Since project requires to be crossplaform Xamarin forms controls seems to be one of the option.
2) Should we go with Custom controls and not Xamarin forms controls?
I just started with Xamarin sample code would appreciate if someone can guide me through this.
1) How would I control opening and closing of Navigation Drawer?
Use this.IsPresented = true; to open and this.IsPresented = false; to close the drawer.
About the other questions I don't understand you good, but depending on your requirements, you should create custom controls or download one from NuGet.
Note:
I believe the most important thing for a beginner is to learn how to implement a native code using DependencyService and also to use Design patterns like MVVM.
You would need to set MasterBehavior = MasterBehavior.Popover on the MasterDetailPage to force it to exhibit the behaviour you are after, otherwise it will default to MasterBehavior.Default, which in Landscape mode will be always open.

Monotouch - NavigationBar with extra padding ios 7

I'm trying to adapt my app for iOS 7. It's written with Xamarin and C#.
I'm having trouble with extra padding for the left button in the navigationbar.
I have a helper method for rendering my back-button which looks like this:
public static UIBarButtonItem GetBackButton (this UIViewController controller)
{
var backImage = new UIImage ("Images/back.png");
var backButton = new UIButton (UIButtonType.Custom);
backButton.Frame = new RectangleF (0, 0, 44, 44);
backButton.SetImage (backImage, UIControlState.Normal);
backButton.TouchUpInside += (object sender, EventArgs e) => {
var cancelBackNavigation = false;
if (controller is UIViewControllerBase) {
if (((UIViewControllerBase)controller).PrepareNavigateBack () != true) {
cancelBackNavigation = true;
}
}
if (cancelBackNavigation == false) {
controller.NavigationController.PopViewControllerAnimated (true);
}
};
return new UIBarButtonItem (backButton);
}
The navigationbar adds lots of padding before the back-button and making the image inside the back-button look very far away from its real position. The code above works fine in iOS 6.
I don't wanna use ContentEdgeInsets cause it will stretch the image and making it ugly.
Anyone with an idea of what to do?
I tried looking up your issue and found out that first, you need to hide the back button as follows:
NavigationItem.HidesBackButton = true;
Then for setting the button, you need to set it this way:
NavigationItem.BackBarButtonItem = yourButton;
That way, you won`t have the extra indentation.
Also you might find the following question useful:
Make a custom back button for UINavigationController
This is how I setup my NavigationBar
controller.View.BackgroundColor = Theme.BackgroundColor;
controller.NavigationItem.SetHidesBackButton (true, false);
controller.NavigationController.Toolbar.TintColor = Theme.BackgroundColor;
controller.NavigationController.NavigationBar.TintColor = Theme.BackgroundColor;
controller.NavigationController.SetNavigationBarHidden (show == false, false);
controller.NavigationController.NavigationBar.BackgroundColor = Theme.BackgroundColor;
controller.NavigationController.NavigationBar.SetTitleTextAttributes (Theme.NavigationBarTextAttributes);
controller.NavigationController.NavigationBar.Subviews [0].Alpha = 0.01f;

Categories

Resources