Xamarin forms splash screen issue - xamarin

A black screen with app title is showing when minimizing the app while loading splash screen , also the first screen will display after some time. Here is my splash activity and main activity classes.
[Activity(Theme = "#style/Theme.Splash", Icon = "#drawable/icon", MainLauncher = true, NoHistory = true,
ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation,
ScreenOrientation = ScreenOrientation.Behind)]
public class SplashActivity : Activity
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
var dpWidth = Resources.DisplayMetrics.WidthPixels/Resources.DisplayMetrics.Density;
RequestedOrientation = dpWidth > 700 ? ScreenOrientation.Unspecified : ScreenOrientation.Portrait;
ThreadPool.QueueUserWorkItem(o => LoadActivity());
}
private void LoadActivity()
{
RunOnUiThread(() => StartActivity(typeof(MainActivity)));
}
public override void OnBackPressed()
{
Environment.Exit(0);
}
}
[Activity(Label = "HACCP", ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public class MainActivity : FormsApplicationActivity
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
ActionBar.SetIcon(Android.Resource.Color.Transparent);
Forms.Init(this, bundle);
// some function //
LoadApplication(new App());
}
}

You tagged Xamarin.Forms so it should be as simple as..
class App : Application
{
public App()
{
MainPage = new MySplashPage();
}
}
class MySplashPage : ContentPage
{
public MySplashPage()
{
Task.Delay(3000); //show my pretty splash for 3 seconds
Application.Current.MainPage = new MyOtherSpiffyPage();
}
}

Not certain if the activity attribute ScreenOrientation = ScreenOrientation.Behind) is causing any issues, we don't use that in our apps.
Here is a "standard" splash activity we do use, letting Xamarin.Android take care of timing etc:
public class SplashActivity : Activity
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
// Start main.
StartActivity(typeof(MainActivity));
}
}
You might try simplifying your app in similar fashion.

Related

Xamarin Forms - Android - initialize libraries in splash activity (before main activity)

My splash screen is Lottie animation, during 3-sec animation I am trying to initialize all I can in the background thread, so I put everything from MainActivity before LoadApplication method in this new activity, just wanted to put everything I can inside splash animation time
here is my splash activity class
[Activity(Label = "MyName", Theme = "#style/MyName.Splash", MainLauncher = true, NoHistory = true)]
public class SplashActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity, IAnimatorListener
{
private Com.Airbnb.Lottie.LottieAnimationView animationView;
public void OnAnimationCancel(Animator animation)
{
}
public void OnAnimationEnd(Animator animation)
{
//StartActivity(new Intent(Application.Context, typeof(MainActivity)));
StartActivity(new Intent(this, typeof(MainActivity)));
Finish(); //if I remove this I got 1-2 sec white screen
}
public async void OnAnimationStart(Animator animation)
{
await Task.Run(() =>
{
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
global::Xamarin.Forms.FormsMaterial.Init(this, savedInstanceState);
OneSignal.Current.StartInit(API_KEY).InFocusDisplaying(OSInFocusDisplayOption.Notification).EndInit();
FFImageLoading.Forms.Platform.CachedImageRenderer.Init(enableFastRenderer: true);
Rg.Plugins.Popup.Popup.Init(this); // ------ this became problem
MainActivity.AppInstance = new App(); //even create Xam App here but don't show it yet
});
}
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.SplashLayout);
animationView = FindViewById<Com.Airbnb.Lottie.LottieAnimationView>(Resource.Id.animation_view);
animationView.AddAnimatorListener(this);
}
}
I put init methods inside the background thread because if it is on the main thread my animation is not fluid.
After the animation ends, I start main activity and show my app
main activity code
[Activity(Label = "MyName", Icon = "#mipmap/ic_launcher", Theme = "#style/MainTheme", MainLauncher = false, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
public static App AppInstance; //Xamarin App instance created on splash activity
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
LoadApplication(AppInstance);
AppInstance.Show(); //just setting MainPage = new AppShell();
}
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
{
Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
everything is working fine, except Rg plugin
if I move Rg.Plugins.Popup.Popup.Init(this); into main activity then it's working.
So my question is am I doing wrong to initialize platform-specific libraries in splash activity, and I why only Rg plugin doesn't work I see in init it asks for Context same as other libraries so I did initialize it with this keyword and starting main activity with this keyword
Should I do it some other way, init libraries while my animation is playing, because every sec counts when you start the application.
Context which Main activity is created is it different one from splash activity?
I even tried to replace all this with Application.Context

Playing a standard/system sound on phone xamarin forms

Is there a standard cross platform way of playing a 250 ms or so 'ding' on Xamarin Forms iOS and Android?
Mark Wardell
You can use DependencyService to play default system notification sound in each platform .
Create IPlaySoundService Interface :
public interface IPlaySoundService
{
void PlaySystemSound();
}
Implement the PlaySystemSound method in iOS as follow:
[assembly: Xamarin.Forms.Dependency(typeof(PlaySoundService))]
namespace AppCarouselViewSample.iOS
{
public class PlaySoundService : IPlaySoundService
{
public void PlaySystemSound()
{
var sound = new SystemSound(1000);
sound.PlaySystemSound();
}
}
}
Implement the PlaySystemSound method in Android as follow :
[assembly:Xamarin.Forms.Dependency(typeof(PlaySoundService))]
namespace AppCarouselViewSample.Droid
{
public class PlaySoundService : IPlaySoundService
{
public void PlaySystemSound()
{
Android.Net.Uri uri = RingtoneManager.GetDefaultUri(RingtoneType.Ringtone);
Ringtone rt = RingtoneManager.GetRingtone(MainActivity.instance.ApplicationContext, uri);
rt.Play();
}
}
}
This is the definition of instance from MainActivity :
namespace xxx.Droid
{
[Activity(Label = "AppCarouselViewSample", Icon = "#mipmap/icon", Theme = "#style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
public static MainActivity instance { set; get; }
protected override void OnCreate(Bundle savedInstanceState)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(savedInstanceState);
instance = this;
Xamarin.Forms.Forms.SetFlags(new string[] { "CarouselView_Experimental", "SwipeView_Experimental", "IndicatorView_Experimental" });
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
LoadApplication(new App());
}
...
}
Then it they will play the default notification Sound in each platform . You can modify SystemSoundID in iOS to fit your wants .Here is the Sound ID list .
here is my now compiling yet crashing Droid implementation
using Android.Media;
using TripCalculator.Droid.Services;
[assembly: Xamarin.Forms.Dependency(typeof(PlaySoundService))]
// Crashes
namespace TripCalculator.Droid.Services
{
public class PlaySoundService : IPlaySoundService
{
public void PlaySystemSound()
{
var currentContext = Android.App.Application.Context;
Android.Net.Uri uri = RingtoneManager.GetDefaultUri(RingtoneType.Ringtone);
Ringtone rt = RingtoneManager.GetRingtone(currentContext.ApplicationContext, uri);
rt.Play();
}
}
}

Backgrounded jobs not working with Shiny library in a simple Xamarin Forms project [duplicate]

This question already has answers here:
How to extend application class in xamarin android
(2 answers)
Closed 3 years ago.
I am trying to implement the very promising Shiny library (for background jobs) from Allan Ritchie. I have only tried this in a simple File/New Project for Android thus far (haven't implemented the code for iOS or UWP), but I am not able to get it to run.
I am following the article https://allancritchie.net/posts/shinyjobs. However, when I run I get the following exception...
And I never hit this breakpoint...
My code can be cloned from https://github.com/JohnLivermore/SampleXamarinApp.git
But here it is inline as well...
App.xaml.cs
public partial class App : Application
{
public App()
{
InitializeComponent();
MainPage = new MainPage();
}
protected override async void OnStart()
{
var job = new JobInfo
{
Identifier = "YourFirstJob",
Type = typeof(YourFirstJob),
// these are criteria that must be met in order for your job to run
BatteryNotLow = false,
DeviceCharging = false,
RequiredInternetAccess = InternetAccess.Any,
Repeat = true //defaults to true, set to false to run once OR set it inside a job to cancel further execution
};
// lastly, schedule it to go - don't worry about scheduling something more than once, we just update if your job name matches an existing one
await ShinyHost.Resolve<Shiny.Jobs.IJobManager>().Schedule(job);
}
protected override void OnSleep()
{
}
protected override void OnResume()
{
}
}
Startup.cs
public class Startup : ShinyStartup
{
public override void ConfigureServices(IServiceCollection services)
{
}
}
YourFirstJob.cs
public class YourFirstJob : IJob
{
public YourFirstJob()
{
}
public async Task<bool> Run(JobInfo jobInfo, CancellationToken cancelToken)
{
//await this.dependency.SomeAsyncMethod(id);
return true; // this is for iOS - try not to lie about this - return true when you actually do receive new data from the remote method
}
}
MainActivity.cs
[Activity(Label = "SampleApp", 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;
base.OnCreate(savedInstanceState);
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
LoadApplication(new App());
}
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
{
Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
Shiny.AndroidShinyHost.OnRequestPermissionsResult(requestCode, permissions, grantResults);
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
MainApplication.cs
[Application]
public class MainApplication : Application
{
public override void OnCreate()
{
base.OnCreate();
Shiny.AndroidShinyHost.Init(this, new SampleApp.Startup());
}
}
Any help would be greatly appreciated!
You might want to add following constructor to your MainApplication class.
public MainApplication(IntPtr handle, JniHandleOwnership ownerShip) : base(handle, ownerShip)
{
}

Xamarin BLE scanning only sometimes

I created simple Xamarin.Forms Bluetooth low energy scanning application. As I will use Bluetooth only on Android, I implemented scanning in MainActivity.cs of Android project:
namespace BlankAppXamlXamarinForms.Droid
{
[Activity(Label = "BlankAppXamlXamarinForms", Icon = "#drawable/icon", Theme = "#style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
private BluetoothManager _manager;
App app;
protected override void OnCreate(Bundle bundle)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(bundle);
global::Xamarin.Forms.Forms.Init(this, bundle);
app = new App();
var appContext = Application.Context;
_manager = (BluetoothManager)appContext.GetSystemService(BluetoothService);
_manager.Adapter.BluetoothLeScanner.StartScan(new MyScanCallback(app));
LoadApplication(new App());
}
}
public class MyScanCallback : ScanCallback
{
App _app;
public MyScanCallback(App app) {
_app = app;
}
public override void OnScanResult(ScanCallbackType callbackType, ScanResult result)
{
_app.newDevice(result.Device.Name + " - " + result.Device.Address);
}
}
}
The problem is that OnScanResult receives advertising packets only a moment after the application is started and when I switch the display of my phone off and then turn it on again. Meanwhile the application receives almost no advertising packets. How to receive advertising packets all the time my application is active?
You are creating two instances of App. Instead of LoadApplication(new App()); you should be passing in your field app, i.e. LoadApplication(app);
Also, instead of starting the scan in OnCreate, you might want to start the scan in OnResume and stop the scan in OnPause e.g.:
public class MainActivity : FormsAppCompatActivity
{
BluetoothManager bleManager;
App app;
ScanCallback scanCallback;
protected override void OnCreate(Bundle bundle)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(bundle);
Forms.Init(this, bundle);
app = new App();
bleManager = (BluetoothManager)Application.Context.GetSystemService(BluetoothService);
scanCallback = new MyScanCallback(app);
LoadApplication(new App());
}
protected override void OnResume()
{
base.OnResume();
bleManager.Adapter.BluetoothLeScanner.StartScan(scanCallback);
}
protected override void OnPause()
{
base.OnPause();
bleManager.Adapter.BluetoothLeScanner.StopScan(scanCallback);
}
}

Xamarin Forms 2.0 AppCompat android keyboard mode

Xamarin I updated to version 4, Forms and 2.0 versions. On Android, I use AppCompat.
I had a problem. Previously, the Android keyboard caused resize view. Now this does not happen. The keyboard appears on the top view. And the desired Elements to be hiding.
I've tried:
[Activity(WindowSoftInputMode = SoftInput.AdjustResize, Label = "Title", Icon = "#drawable/icon", Theme = "#style/MyTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
global::Xamarin.Forms.Forms.Init(this, bundle);
ToolbarResource = Resource.Layout.toolbar;
TabLayoutResource = Resource.Layout.tabs;
LoadApplication(new App());
Window.DecorView.SetFitsSystemWindows(true);
}
}
Daylight AppCompat has been made on this lesson: https://blog.xamarin.com/material-design-for-your-xamarin-forms-android-apps/
Thank you.
I have solved the problem. Decompile class
"Forms AppCompatActivity" and watched how the method works OnCreate.
As a result, I turned out the following code:
[Activity(Label = "Title", Icon = "#drawable/icon", Theme = "#style/MyTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
global::Xamarin.Forms.Forms.Init(this, bundle);
Window.SetSoftInputMode(SoftInput.AdjustResize);
AndroidBug5497WorkaroundForXamarinAndroid.assistActivity(this);
ToolbarResource = Resource.Layout.toolbar;
TabLayoutResource = Resource.Layout.tabs;
LoadApplication(new App());
}
public class AndroidBug5497WorkaroundForXamarinAndroid
{
// For more information, see https://code.google.com/p/android/issues/detail?id=5497
// To use this class, simply invoke assistActivity() on an Activity that already has its content view set.
// CREDIT TO Joseph Johnson (http://stackoverflow.com/users/341631/joseph-johnson) for publishing the original Android solution on stackoverflow.com
public static void assistActivity(Activity activity)
{
new AndroidBug5497WorkaroundForXamarinAndroid(activity);
}
private Android.Views.View mChildOfContent;
private int usableHeightPrevious;
private FrameLayout.LayoutParams frameLayoutParams;
private AndroidBug5497WorkaroundForXamarinAndroid(Activity activity)
{
FrameLayout content = (FrameLayout)activity.FindViewById(Android.Resource.Id.Content);
mChildOfContent = content.GetChildAt(0);
ViewTreeObserver vto = mChildOfContent.ViewTreeObserver;
vto.GlobalLayout += (object sender, EventArgs e) => {
possiblyResizeChildOfContent();
};
frameLayoutParams = (FrameLayout.LayoutParams)mChildOfContent.LayoutParameters;
}
private void possiblyResizeChildOfContent()
{
int usableHeightNow = computeUsableHeight();
if (usableHeightNow != usableHeightPrevious)
{
int usableHeightSansKeyboard = mChildOfContent.RootView.Height;
int heightDifference = usableHeightSansKeyboard - usableHeightNow;
frameLayoutParams.Height = usableHeightSansKeyboard - heightDifference;
mChildOfContent.RequestLayout();
usableHeightPrevious = usableHeightNow;
}
}
private int computeUsableHeight()
{
Rect r = new Rect();
mChildOfContent.GetWindowVisibleDisplayFrame(r);
if (Build.VERSION.SdkInt < BuildVersionCodes.Lollipop)
{
return (r.Bottom - r.Top);
}
return r.Bottom;
}
}
}
It is important to add "Window.SetSoftInputMode(SoftInput.AdjustResize);" After calling base.OnCreate(bundle);

Resources