I am trying to implement an splash screen for the Android part of my UNO solution. I can get the splash screen to appear, wait a few seconds but upon navigation to the main page I get the following exception in the app.cs
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
#if DEBUG
if (System.Diagnostics.Debugger.IsAttached)
{
// this.DebugSettings.EnableFrameRateCounter = true;
}
#endif
Frame rootFrame = Windows.UI.Xaml.Window.Current.Content as Frame;
// Do not repeat app initialization when the Window already has content,
// just ensure that the window is active
if (rootFrame == null)
{
// Create a Frame to act as the navigation context and navigate to the first page
rootFrame = new Frame(); <<<<< exception
Unhandled Exception:
Java.Lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.Resources android.content.Context.getResources()' on a null object reference occurred
The stack trace is as simple as :
0x25 in Uno1.App.OnLaunched at C:\Users\pjsta\Documents\Visual Studio 2017\Projects\Uno1\Uno1\Uno1.Shared\App.xaml.cs:55,17 C#
The relevant part of the solution are
1. my new SplashActivity in the Android project
[Activity(Label = "SplashScreen", MainLauncher = true, Theme = "#style/Theme.SplashActivity")]
public class SplashActivity : Activity
{
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
System.Threading.Thread.Sleep(1000);
StartActivity(typeof(MainActivity));
}
}
Modification to MainActivity to not be the MainLauncher
[Activity(
MainLauncher = false,
ConfigurationChanges = ConfigChanges.Orientation |
ConfigChanges.ScreenSize,
WindowSoftInputMode = SoftInput.AdjustPan | SoftInput.StateHidden )]
public class MainActivity : Windows.UI.Xaml.ApplicationActivity
{
}
The relevant style loads fo the splash screen OK. Switching the MainActivity back to MainLauncher=true works , albeit without a splash screen.
I am a newbie to Xamarin and Android development, but competent in UWP. Anyone out there got any ideas?
From the exception, it sounds like when new Frame() is called, the base native constructor is called with a null Context. This is probably because Uno expects ApplicationActivity to be run as MainLauncher=true. It's possible that inheriting your SplashActivity class from Uno.UI.BaseActivity could resolve the error.
A better way to show a splash screen on Android is to modify the theme rather than create a separate activity. I'll use the Uno Gallery app as an example.
Create a file in the Resources/drawable folder of your Android head called, eg, splash.xml. Define your splash screen visual appearance here.
Open the Resources/values/Styles.xml file. Inside the 'AppTheme' style add the following line:
<item name="android:windowBackground">#drawable/splash</item>
Hope that helps. Also, please tag questions about the Uno Platform as 'uno-platform' (the 'uno' tag refers to the OpenOffice component model).
Related
The new API SplashScreen in Android 12 seems good but just like before the sample code in the documentation does not really help explaining the whole and proper implementation. There is also some cases where you might do some task during splash screen in our case this is to launch Firebase Auth so probably the best way is just to opt out on using this new featured API but according to lint warning it seems like it is mandatory and there is no way to opt out.
The application should not provide its own launch screen
Application-defined Launch Screen Starting in Android 12 (API 31+),
the application's Launch Screen is provided by the system and the
application should not create its own, otherwise the user will see two
splashscreen. Please check the SplashScreen class to check how the
Splash Screen can be controlled and customized.
How about the backward compatibility for older devices, how to handle it? Is there any codelab project to play and test with?
Can we opt out of SplashScreen?
It looks like we can't opt out as Android Team is trying to unify the app loading experience: https://9to5google.com/2021/04/21/android-12-dp3-all-apps-now-show-the-same-splash-screen-while-loading-gallery/
How to use it?
If you don't do anything then it will use windowBackground of the theme & your launcher icon & dismissed as soon as your app draws its first frame.
There are bunch of properties that you can modify like background, icon etc: https://developer.android.com/about/versions/12/features/splash-screen#set-theme
What if I want splash to stay longer? Like fetching a local DataBase.
You can use ViewTreeObserver.OnPreDrawListener & make a blocking call from your viewmodel return if it's ready to go ahead.
Activity:
// My Launcher Activity
class MainActivity : AppCompatActivity() {
private val viewModel : JustDelayViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val content: View = findViewById(android.R.id.content)
content.viewTreeObserver.addOnPreDrawListener(
object : ViewTreeObserver.OnPreDrawListener {
override fun onPreDraw(): Boolean {
// Check if the initial data is ready.
return if (viewModel.getIsReady()) {
// The content is ready; start drawing.
content.viewTreeObserver.removeOnPreDrawListener(this)
true
} else {
// The content is not ready; suspend.
false
}
}
}
)
}
}
ViewModel:
class JustDelayViewModel : ViewModel() {
fun getIsReady(): Boolean {
val result = viewModelScope.runCatching {
runBlocking {
//do some blocking call check for Firebase result or something
delay(5000)
}
true //return the result
}
return result.isSuccess
}
}
You can read more about this: https://developer.android.com/about/versions/12/features/splash-screen#suspend-drawing
To complement Mayur's answer for older device support.
The new windowSplashScreen* attributes need to be added in the res/values-v31/style.xml file.
Then for the legacy splashscreen it depend of the current implementation of the app.
If the application simply uses a starting theme with a custom windowBackground there is nothing to do since the windowBackground isn't used for the new splash screen (only if it's a simple color).
If the application has some visible splash screen Activity, there will be a double splash screen on Android 12. To solve this, the application can migrate to the windowBackground solution.
If the application really need to keep its splash screen Activity, it can update the layout to match the system splash screen on Android 12 and/or create a smooth transition from the system splash screen to the app splash screen using the SplashScreen.setOnExitAnimationListener()
We can also use android's splash screen library - link
android {
compileSdk 31
...
}
dependencies {
...
implementation 'androidx.core:core-splashscreen:1.0.0-alpha02'
}
This will give splash screen options in style.xml, you just need to create 2 style.xmls 1 for android api 31 and above and one of below api 31
<style name="Theme.CustomSplashScreenTheme" parent="Theme.SplashScreen">
<item name="windowSplashScreenBackground">#color/white</item>
<item name="windowSplashScreenAnimatedIcon">#drawable/logo</item>
<item name="windowSplashScreenAnimationDuration">300</item>
<item name="postSplashScreenTheme">#style/Theme.YourAppTheme</item>
</style>
Learn more about this library using this example
you can add this line:
<item name="android:windowIsTranslucent">true</item>
in your style.xml file before close style tag. it`s make your default android splash transparent!
Following this tutorial, after I created the project, there is already an error, and I haven't done anything yet:
The name 'Resource' does not exist in the current context
using Android.App;
using Android.Widget;
using Android.OS;
namespace Phoneword
{
[Activity(Label = "Phoneword", MainLauncher = true)]
public class MainActivity : Activity
{
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main); <-- Error here
}
}
}
Tried the answers here, but didn't work.
Checked this link, but as I said, I haven't done or add anything, so it does not work for me
Tried Clean, Rebuild, Build, Restart but still the same
Tried changing Build Action to None. Although the error disappeared, a new one appeared when debugging
The weird thing is I can start debugging even if there is an error. Sometimes it is okay, but after a minute it will produce the red underline, but the word Resource has a color
What would be the way/setup to completely remove this error?
This is my first Xamarin app. I have my environment set up in Visual Studio, and have a template project which I can run in the Android emulator.
Having dragged and dropped a couple of controls on to the designer surface, I find that when I run the application in the emulator, neither of the two controls that I have added (a button and a switch) display in the emulator.
I have tried:
Cleaning the solution
Rebuilding the solution
Manually deleting bin and object files
Unchecking 'Use Fast Deployment' in project Android Options
Uninstalling from the emulator
But with the same result each time.
[Project files removed]
Am I missing something?
Just downloaded your code and ran it. Uncommenting SetContentView (Resource.Layout.Main); it worked to me.
[Activity(Label = "Tgo.AndroidApp", MainLauncher = true, Icon = "#drawable/icon")]
public class MainActivity : Activity
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
// Set our view from the "main" layout resource
SetContentView (Resource.Layout.Main);
}
}
Here a nice guide to get you started with Xamarin Android.
navigate to MainActivity.cs and uncomment this code
SetContentView (Resource.Layout.Main);
and rebuild the solution and debug.
Let me know it if helps!
In my case, I had to update my Main.xml file with the updates I put into the Main.axml and Rebuild.
i've tried in every way to call the requestWindowFeature method, first inside a page script (but raised a very nice error), second on app js, working inside application.launchEvent closure:
var application = require("application");
application.mainModule = "main-page";
application.cssFile = "./app.css";
application.on(application.launchEvent, function (args) {
if (args.android) {
// How to work with android activity in this closure?
}
});
application.start();
I was not able to get an android activity instance in order to hide the default title bar.
Assuming that the "launchEvent" event it is assimilable to "onCreate" event, is there a way to get the android activity in this context? Or is necessary to assume that it isn't the proper way in order to achieve the goal?
For the time being you can try this:
application.on(application.launchEvent, function (args) {
if (application.android) {
var activity = application.android.startActivity;
// Do something with activity...
}
});
Our next release will include Android Activity Events. Here is the pull request.
At the top-left corner of the main activity of my Xamarin Android app (using API 23) I currently have a simple text that is set with the command below.
[Activity(Label = "Activity Name", MainLauncher = true, Icon = "#drawable/appIcon", ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation, ScreenOrientation = ScreenOrientation.Portrait)]
This line is put just before the
public class MainActivity : Activity
{
// code for main activity
}
and as a result I can see the text "Activity Name" in the top-left corner of my app.
I was wondering how can I use an image instead in that top-left corner. I have seen that the Label property of the Activity class only accept a string, so the changing the Label won't work. But I have seen apps that have some icon or image rather than the activity name, so I was wondering what is the process to achieve this?
EDIT
I have tried with the following lines in the OnCreate() method of the MainActivity:
var actionBar = this.ActionBar;
actionBar.SetIcon(Resource.Drawable.appIcon);
actionBar.SetLogo(Resource.Drawable.appIcon);
//actionBar.SetIcon(Resources.GetDrawable(Resource.Drawable.appIcon));
but none of them works. There is no error, it just doesn't show any image but only the original text I passed as Label (in my example "Activity Name").
I also tried removing the label completely cause I thought it might take the whole space where the image is supposed to be shown, but that still doesn't solve my issue. I did this by adding also:
actionBar.SetDisplayShowTitleEnabled(false);
I am sure this is the right place for the code since if I use actionBar.Subtitle I can see the subtitle is added correctly in the action bar.
Not sure if this is relevant, but I also have the following in the AssemblyInfo.cs
[assembly: Application(Theme = "#android:style/Theme.Material.Light")]
As mentioned, I am using Xamarin and API 23, to make my app comparinle,with Android 6.0+.
Try to use the following code
var actionBar = ((Activity)Context).ActionBar;
actionBar.SetIcon(Resource.Drawable.newIcon);// add the newIcon in the folder Drawable
I found the solution. I just had to add:
var actionBar = this.ActionBar;
actionBar.SetDisplayShowHomeEnabled(true);
actionBar.SetIcon(Resource.Drawable.appIcon);
SetDisplayShowHomeEnabled will force the icon to be shown.