find device orientation, not app orientation using xamarin forms - xamarin.forms

I am using xamarin forms for my app. Bascially My app need portrait mode orientation. But When i click on the button on my page, I need to find whether my device is on portrait or landscape. But my app orientation is always showing portrait mode.
MainActivity.cs:
using System;
using Android.App;
using Android.Content.PM;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;
using Android.Content;
using Xamarin.Forms;
using Plugin.CurrentActivity;
namespace App2.Droid
{
[Activity(Label = "App2", Icon = "#mipmap/icon", Theme = "#style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
protected override void OnCreate(Bundle savedInstanceState)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
if (!isPad(this))
{
RequestedOrientation = ScreenOrientation.Portrait;
}
else
{
RequestedOrientation = ScreenOrientation.Portrait;
}
CrossCurrentActivity.Current.Activity = this;
base.OnCreate(savedInstanceState);
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
LoadApplication(new App());
}
public static bool isPad(Context context)
{
return (context.Resources.Configuration.ScreenLayout & Android.Content.Res.ScreenLayout.SizeMask) >= Android.Content.Res.ScreenLayout.SizeLarge;
}
public override void OnConfigurationChanged(Android.Content.Res.Configuration newConfig)
{
base.OnConfigurationChanged(newConfig);
switch (newConfig.Orientation)
{
case Android.Content.Res.Orientation.Portrait:
switch (Device.Idiom)
{
case TargetIdiom.Phone:
LockRotation(Orientation.Vertical);
break;
case TargetIdiom.Tablet:
LockRotation(Orientation.Horizontal);
break;
}
break;
case Android.Content.Res.Orientation.Landscape:
switch (Device.Idiom)
{
case TargetIdiom.Phone:
LockRotation(Orientation.Vertical);
break;
case TargetIdiom.Tablet:
LockRotation(Orientation.Horizontal);
break;
}
break;
}
}
private void LockRotation(Orientation orientation)
{
switch (orientation)
{
case Orientation.Vertical:
RequestedOrientation = ScreenOrientation.Portrait;
break;
case Orientation.Horizontal:
RequestedOrientation = ScreenOrientation.Landscape;
break;
}
}
}
}
TestPage.xaml.cs:
private void btnsubmit_Clicked(object sender, EventArgs e)
{
lblText.Text = CrossDeviceOrientation.Current.CurrentOrientation.ToString();
}
But it is showing always portrait(App Orientation). But I need device orientation.
Please help me to resolve this issue

You can use Xamarin.Essentials: Device Display Information to achieve it.
Here is my code, when device change the Orientation, will push a Alert to show the device Orientation.
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
DeviceDisplay.MainDisplayInfoChanged += OnMainDisplayInfoChanged;
}
private void OnMainDisplayInfoChanged(object sender, DisplayInfoChangedEventArgs e)
{
// throw new NotImplementedException();
DisplayAlert("Info", e.DisplayInfo.Orientation.ToString() + " ", "OK");
}
}
Here is running GIF.

Related

Splashscreen not appearing when app is open and in background in iOS

I am using a Xamarin Forms application with Azure push notification. I need to redirect to a splash screen when my push notification is clicked. Android working fine. But in iOS a splash screen is not visible.
I tried the below example. But it's not hitting on the OnAppearing() method.
example
This is my splash screen code
public Splash(string PushNotification)
{
PushNotificationPage = PushNotification;
LoadSettings();
NavigationPage.SetHasNavigationBar(this, false);
var sub = new AbsoluteLayout {
BackgroundColor = Code.Application.Instance.CurrentReources.SplashScreenBackground
};
splashImage = new Image
{
Source = SplashImage
};
AbsoluteLayout.SetLayoutFlags(splashImage, AbsoluteLayoutFlags.PositionProportional);
AbsoluteLayout.SetLayoutBounds(splashImage, new Rectangle(0.5, 0.5, AbsoluteLayout.AutoSize, AbsoluteLayout.AutoSize));
sub.Children.Add(splashImage);
if (Device.RuntimePlatform == Device.Android)
{
splashImage.HeightRequest = 270;
splashImage.WidthRequest = 270;
}
this.Content = sub;
}
protected override async void OnAppearing()
{
(App.Current as App).OnResumeHandler += Handle_OnResumeHandler;
base.OnAppearing();
splashImage.Opacity = 0;
await splashImage.FadeTo(1, 3000);
Xamarin.Forms.Application.Current.MainPage = new NavigationPage(new LoginPage(PushNotificationPage));
}
void Handle_OnResumeHandler(object sender, EventArgs e)
{
Console.WriteLine("OnPauseResumeWithPage");
}
protected override void OnDisappearing()
{
(App.Current as App).OnResumeHandler -= Handle_OnResumeHandler;
base.OnDisappearing();
}
Also added below method to App.cs
protected override void OnSleep()
{
OnSleepHandler?.Invoke(null, new EventArgs());
}
protected override void OnResume()
{
OnResumeHandler?.Invoke(null, new EventArgs());
}
I don't know this is programmatically good or bad. But its work for me now. I have call OnDisappearing() method inside splash method. Its loading only if my push notification clicked. so its work for me without issue.
if(PushNotification!=null)
{
OnAppearing();
}

Set DarkMode on the first page status bar xamarin forms android

Using xamarin forms and we are adding ability to switch between Dark-Light mode. All is good however the first page of the app in android whatever I do the status bar color wont change.
I guess that in the android project I have to call SetTheme(...) before OnCreate.
Or Am I missing something here?
Question
How do you set the status bar color depending on theme? code below does not change once the android has loaded
public void SetStatusBarColor(System.Drawing.Color color, bool darkStatusBarTint)
{
var activity = Platform.CurrentActivity;
var window = activity.Window;
window?.AddFlags(WindowManagerFlags.DrawsSystemBarBackgrounds);
window?.ClearFlags(WindowManagerFlags.TranslucentStatus);
window?.SetStatusBarColor(color.ToPlatformColor());
var flag = (StatusBarVisibility)SystemUiFlags.LightStatusBar;
if (window != null)
{
window.DecorView.SystemUiVisibility = darkStatusBarTint ? flag : 0;
}
}
Suggestions?
thanks
Try this:
private void SetStatusBarColor(System.Drawing.Color color, bool darkStatusBarTint)
{
var activity = Platform.CurrentActivity;
var window = activity.Window;
if (window != null)
{
window.AddFlags(WindowManagerFlags.DrawsSystemBarBackgrounds);
window.ClearFlags(WindowManagerFlags.TranslucentStatus);
window.SetStatusBarColor(color.ToPlatformColor());
StatusBarVisibility flags = default;
if (darkStatusBarTint)
flags |= (StatusBarVisibility)SystemUiFlags.LightStatusBar;
else
flags &= ~(StatusBarVisibility)SystemUiFlags.LightStatusBar;
window.DecorView.SystemUiVisibility = flags;
}
}
Or
private void SetStatusBarColor(System.Drawing.Color color, bool darkStatusBarTint)
{
var activity = Platform.CurrentActivity;
var window = activity.Window;
if (window != null)
{
window.AddFlags(WindowManagerFlags.DrawsSystemBarBackgrounds);
window.ClearFlags(WindowManagerFlags.TranslucentStatus);
window.SetStatusBarColor(color.ToPlatformColor());
window.DecorView.SystemUiVisibility = darkStatusBarTint
? (StatusBarVisibility)SystemUiFlags.LightStatusBar
: StatusBarVisibility.Visible;
}
}
Both functions work.
You can update the StatusBar color in the MainActivity.OnCreate method and also listen to the App.Current.RequestedThemeChanged event.
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
LoadApplication(new App());
ApplyStatusBarColor(App.Current.RequestedTheme);
App.Current.RequestedThemeChanged += (s, e) => ApplyStatusBarColor(e.RequestedTheme);
}
private void ApplyStatusBarColor(Xamarin.Forms.OSAppTheme osAppTheme)
{
if (osAppTheme == Xamarin.Forms.OSAppTheme.Dark)
SetStatusBarColor(Xamarin.Forms.Color.Blue, false);
else
SetStatusBarColor(Xamarin.Forms.Color.Yellow, true);
}
}

Xamarin.Forms change the color of the buttons and border color in alertDialog

I have AlertDialog. Bu default the alertDialog is like this:
I want to change the color of OK button and add border color. Is there a solution for this customization .
This is my code:
await Application.Current.MainPage.DisplayAlert("Alert!", " This is DisplayAlert", "OK");
You could use [DependencyService] to call native AlerDialog and change it in specific platforms,here is a simple sample that change the color of the action button .
in Forms ,create the interface:
public interface IPopUp
{
void Popup(string title, string message,Color titleColor,Color messageColor,Color OKButtonColor ,EventHandler handler);
}
in iOS
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using App10.iOS;
using Foundation;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
using App10;
[assembly: Dependency(typeof(PopupImplemention))]
namespace App10.iOS
{
public class PopupImplemention : IPopUp
{
public void Popup(string title, string message, Color titleColor, Color messageColor, Color OKButtonColor, EventHandler handler)
{
UIAlertController alertController = UIAlertController.Create(title,message,UIAlertControllerStyle.Alert);
var firstAttributes = new UIStringAttributes
{
ForegroundColor =titleColor.ToUIColor(),
};
var secondAttributes = new UIStringAttributes
{
ForegroundColor =messageColor.ToUIColor(),
};
alertController.SetValueForKey(new NSAttributedString(title, firstAttributes), new NSString("attributedTitle"));
alertController.SetValueForKey(new NSAttributedString(message, secondAttributes), new NSString("attributedMessage"));
UIAlertAction cancelAction = UIAlertAction.Create("Cancel",UIAlertActionStyle.Cancel,null);
UIAlertAction okAction = UIAlertAction.Create("OK", UIAlertActionStyle.Default,(sender)=> { handler?.Invoke(sender, new EventArgs()) ; });
okAction.SetValueForKey(OKButtonColor.ToUIColor(), new NSString("_titleTextColor"));
alertController.AddAction(cancelAction);
alertController.AddAction(okAction);
var currentViewController = topViewControllerWithRootViewController(UIApplication.SharedApplication.Delegate.GetWindow().RootViewController);
currentViewController.PresentViewController(alertController,true,null);
}
UIViewController topViewControllerWithRootViewController(UIViewController rootViewController)
{
if (rootViewController is UITabBarController)
{
UITabBarController tabBarController = (UITabBarController)rootViewController;
return topViewControllerWithRootViewController(tabBarController.SelectedViewController);
}
else if (rootViewController is UINavigationController)
{
UINavigationController navigationController = (UINavigationController)rootViewController;
return topViewControllerWithRootViewController(navigationController.VisibleViewController);
}
else if (rootViewController.PresentedViewController != null)
{
UIViewController presentedViewController = rootViewController.PresentedViewController;
return topViewControllerWithRootViewController(presentedViewController);
}
else
{
return rootViewController;
}
}
}
}
in Android
in MainActivity
public static MainActivity Intance;
protected override void OnCreate(Bundle savedInstanceState)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(savedInstanceState);
Intance = this;
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
LoadApplication(new App());
}
using Xamarin.Forms;
using xxx;
using xxx.Droid;
using Android;
using System;
using Xamarin.Forms.Platform.Android;
using Android.Support.V7.App;
using Android.Text;
[assembly: Dependency(typeof(PopupImplemention))]
namespace xxx.Droid
{
public class PopupImplemention : IPopUp
{
public void Popup(string title, string message, Color titleColor, Color messageColor, EventHandler handler)
{
// because html.string could not support format string , so you need to set the color directly in the string with a static value
Android.Support.V7.App.AlertDialog.Builder alert = new Android.Support.V7.App.AlertDialog.Builder(MainActivity.Intance);
alert.SetTitle(title);
alert.SetMessage(message);
alert.SetPositiveButton(Html.FromHtml("<font color='#0000ff'>OK</font>"), (senderAlert, args) =>
{
handler?.Invoke(senderAlert, args);
});
Android.Support.V7.App.AlertDialog dialog = alert.Create();
dialog.Show();
}
}
}
And call it in forms
DependencyService.Get<IPopUp>().Popup("Title","xxxxxxxxxxxx",Color.Red,Color.Blue,Color.Green,(sen,args)=> {
// handle the logic when clikc the OK button
});
You can use cross platform libraries like this one: https://github.com/aritchie/userdialogs
You will need to create a styles.xml and configure it for Android that way. There is currently no way to customize that native control through any of the Xamarin.Forms API's as far as I am aware.
Example:
<style name="AppCompatAlertDialogStyle" parent="Theme.AppCompat.Dialog.Alert">
<item name="colorAccent">#c7ac56</item>
<item name="android:textColor">#c7ac56</item>
<item name="android:background">#5c8487</item>
</style>
Here is a good tutorial on an example on how to do this: http://gmariotti.blogspot.com/2015/04/a-material-styled-alertdialog.html
If you are using Xamarin Android you probably could also hook into the AlertDialog.Builder and set the proprieties pro grammatically: https://developer.android.com/reference/android/app/AlertDialog.Builder

Banner Advertisement with Xamarin.Forms

I just want to know about the banner advertisements supported with Xamarin.Forms without any patch or loophole. Is there any advertisement provider who are providing their SDKs with the Xamarin.Forms?
Thanks in advance.
There are both SDK and step-by-step examples for Google AdMob for Xamarin.Android. You are going to need the Xamarin.GooglePlaySerives.Ads nuget.
I use it to show ads in my Xamarin.Forms app published at Google Play.
Here is the sample code for the android part of your application:
using System;
using Android.App;
using Android.Content;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;
using Android.Support.V7.App;
using Android.Gms.Ads;
using Android;
namespace AdMobExample
{
[Activity (Label = "#string/app_name", MainLauncher = true)]
public class MainActivity : AppCompatActivity
{
protected AdView mAdView;
protected InterstitialAd mInterstitialAd;
protected Button mLoadInterstitialButton;
protected override void OnCreate (Bundle savedInstanceState)
{
base.OnCreate (savedInstanceState);
SetContentView (Resource.Layout.activity_main);
mAdView = FindViewById<AdView> (Resource.Id.adView);
var adRequest = new AdRequest.Builder ().Build ();
mAdView.LoadAd (adRequest);
mInterstitialAd = new InterstitialAd (this);
mInterstitialAd.AdUnitId = GetString (Resource.String.test_interstitial_ad_unit_id);
mInterstitialAd.AdListener = new AdListener (this);
mLoadInterstitialButton = FindViewById<Button> (Resource.Id.load_interstitial_button);
mLoadInterstitialButton.SetOnClickListener (new OnClickListener (this));
}
protected void RequestNewInterstitial ()
{
var adRequest = new AdRequest.Builder ().Build ();
mInterstitialAd.LoadAd (adRequest);
}
protected void BeginSecondActivity ()
{
var intent = new Intent (this, typeof(SecondActivity));
StartActivity (intent);
}
protected override void OnPause ()
{
if (mAdView != null) {
mAdView.Pause ();
}
base.OnPause ();
}
protected override void OnResume ()
{
base.OnResume ();
if (mAdView != null) {
mAdView.Resume ();
}
if (!mInterstitialAd.IsLoaded) {
RequestNewInterstitial ();
}
}
protected override void OnDestroy ()
{
if (mAdView != null) {
mAdView.Destroy ();
}
base.OnDestroy ();
}
class AdListener : Android.Gms.Ads.AdListener
{
MainActivity that;
public AdListener (MainActivity t)
{
that = t;
}
public override void OnAdClosed ()
{
that.RequestNewInterstitial ();
that.BeginSecondActivity ();
}
}
class OnClickListener : Java.Lang.Object, View.IOnClickListener
{
MainActivity that;
public OnClickListener (MainActivity t)
{
that = t;
}
public void OnClick (View v)
{
if (that.mInterstitialAd.IsLoaded) {
that.mInterstitialAd.Show ();
} else {
that.BeginSecondActivity ();
}
}
}
}
}
There is also a ste-by-step guide for AdMob ads for Xamarin.iOS:
using Google.MobileAds;
...
const string intersitialId = "<Get your ID at google.com/ads/admob>";
Interstitial adInterstitial;
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
CreateAndRequestInterstitial ();
}
public void AfterSomeTime ()
{
if (adInterstitial.IsReady)
adInterstitial.PresentFromRootViewController (navController);
}
void CreateAndRequestInterstitial ()
{
adInterstitial = new Interstitial (intersitialId);
adInterstitial.ScreenDismissed += (sender, e) => {
// Interstitial is a one time use object. That means once an interstitial is shown, HasBeenUsed
// returns true and the interstitial can't be used to load another ad.
// To request another interstitial, you'll need to create a new Interstitial object.
adInterstitial.Dispose ();
adInterstitial = null;
CreateAndRequestInterstitial ();
};
var request = Request.GetDefaultRequest ();
// Requests test ads on devices you specify. Your test device ID is printed to the console when
// an ad request is made. GADBannerView automatically returns test ads when running on a
// simulator. After you get your device ID, add it here
request.TestDevices = new [] { Request.SimulatorId.ToString () };
adInterstitial.LoadRequest (request);
}

FragmentDialog loose reference to activity

I am using the support library to create dialogs using fragments.
And i Have the following code to show and dismiss the dialogs:
#Override
public void onCreate(Bundle savedInstanceState) {
Log.d("Create", "Create");
setContentView(R.layout.activity_report);
init();
addListeners();
addhandlerListener();
super.onCreate(savedInstanceState);
}
private void showDialog(final Class<?> classs) {
if (classs.equals(AddressValidateProgress.class)) {
addressValidateProgress = AddressValidateProgress.newInstance();
addressValidateProgress.show(getSupportFragmentManager(), null);
Log.d("counter", "+1");
}
if (classs.equals(GPSSearchProgress.class)) {
showDialog(gpsSearchloadId);
}
}
private void dismissDialog(final Class<?> classs) {
if (classs.equals(AddressValidateProgress.class)) {
FragmentTransaction ft = getSupportFragmentManager()
.beginTransaction();
ft.remove(addressValidateProgress).commitAllowingStateLoss();
addressValidateProgress = null;
Log.d("super", addressValidateProgressId + ":dismissed");
}
if (classs.equals(AddressChooseDialog.class)) {
FragmentTransaction ft = getSupportFragmentManager()
.beginTransaction();
ft.remove(addressChooseDialog).commitAllowingStateLoss();
addressChooseDialog = null;
}
if (classs.equals(GPSSearchProgress.class)) {
dismissDialog(gpsSearchloadId);
Log.d("super", gpsSearchloadId + ":dismissed");
}
}
If i start the application in portrait mode i can use the dialogs normally, i can even rotate the screen and the dialogs are reconstructed.
The problem is that if i start the application rotate the screen and click the button that open the dialogs i get an exception:
java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
Solution found.
It was caused by a static Handler declared

Resources