5

I have been working on this for some time and unfortunately I've not been able to achieve the desired effect without using an image. I have researched on Stack Overflow and almost everywhere and still found no solution that does exactly this.

What I am still trying to do is this:

  • Phone is in light mode > Splash screen has a white background with the word ABC in black in the center

  • Phone is in dark mode > Splash screen has a black background with the word ABC in white in the center

Here is what I have so far:

SplashActivity.cs

namespace Japanese.Droid
{
    [Activity(Label = "Anki+", Theme = "@style/LaunchTheme", MainLauncher = true, NoHistory = true)]
    public class SplashActivity : Activity
    {

styles.xaml

<style name="LaunchTheme" parent="Theme.AppCompat">
    <item name="android:windowBackground">@drawable/splash_screen</item>
    <item name="android:navigationBarColor">#ffffff</item>
</style>

splash_screen.xaml

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@android:color/white"/>
    <item>
        <bitmap android:src="@drawable/splash_logo"
                android:tileMode="disabled"
                android:gravity="center"
                android:layout_gravity="center"/>
    </item>
</layer-list>

splash_screen_night.xaml

<?xml version="1.0" encoding="UTF-8" ?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@android:color/black"/>
    <item>
        <bitmap android:src="@drawable/splash_logo"
                android:tileMode="disabled"
                android:gravity="center"
                android:layout_gravity="center"/>
    </item>
</layer-list>

splash_activity

using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Support.V7.App;
using Android.Views;

namespace Test.Droid
{
    [Activity(Label = "Test+", Theme = "@style/LaunchTheme", MainLauncher = true, NoHistory = true)]
    public class SplashActivity : Activity
    {

        public override void OnCreate(Bundle savedInstanceState, PersistableBundle persistentState)
        {
            base.OnCreate(savedInstanceState, persistentState);

            //==================================== Code to hide the bottom 3 buttons on Android.
            int uiOptions = (int)Window.DecorView.SystemUiVisibility;
            uiOptions |= (int)SystemUiFlags.LowProfile;
            uiOptions |= (int)SystemUiFlags.Fullscreen;
            uiOptions |= (int)SystemUiFlags.HideNavigation;
            uiOptions |= (int)SystemUiFlags.ImmersiveSticky;
            Window.DecorView.SystemUiVisibility = (StatusBarVisibility)uiOptions;
            //===================================

            base.SetTheme(Resource.Style.MainTheme);
            Xamarin.Essentials.Platform.Init(this, savedInstanceState);
        }

        // Launches the startup task
        protected override void OnResume()
        {
            base.OnResume();

            //==================================== Code to hide the bottom 3 buttons on Android.
            int uiOptions = (int)Window.DecorView.SystemUiVisibility;
            uiOptions |= (int)SystemUiFlags.LowProfile;
            uiOptions |= (int)SystemUiFlags.Fullscreen;
            uiOptions |= (int)SystemUiFlags.HideNavigation;
            uiOptions |= (int)SystemUiFlags.ImmersiveSticky;
            Window.DecorView.SystemUiVisibility = (StatusBarVisibility)uiOptions;
            //===================================

            System.Threading.Tasks.Task startupWork = new System.Threading.Tasks.Task(() => { SimulateStartup(); });
            startupWork.Start();
        }


        // Simulates background work that happens behind the splash screen
        async void SimulateStartup()
        {
            await System.Threading.Tasks.Task.Delay(1000); // Simulate a bit of startup work.
            StartActivity(new Intent(Application.Context, typeof(MainActivity)));
        }

        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);
        }

        public override void OnBackPressed() { }
    }
}

This uses an image but I would like to do it with text.

Does anyone know of a way to do it. I've researched this as much as possible, asked for help from two Android devs but still nobody can come up with a simple solution to do this without using an image.

Is it possible to do this with text only and not an image for my Xamarin Android application?

halfer
  • 19,824
  • 17
  • 99
  • 186
Alan2
  • 23,493
  • 79
  • 256
  • 450
  • 1
    Splash Screens Are Evil, Don't Use Them! https://cyrilmottier.com/2012/05/03/splash-screens-are-evil-dont-use-them/ – lenik Mar 06 '20 at 00:30
  • (Hi Alan, a quick aside. With some new users I find it is quite common for their questions to include much boilerplate about how their post definitely is not a duplicate, and as an editor I tend to remove this from their posts. It is fair that this principle is applied to established users too. The principles are two-fold: (1) most readers of posts don't sign in or vote, and so the material is not relevant to most of the readership, and (2) we want question authors to be open to the possibility they just missed a duplicate. Thanks!). – halfer Mar 09 '20 at 07:57
  • Hi Alan i think my answer is what you need. 1) it uses text instead of image for "ABC". 2) it is simple and needs the least code. so take a look at it, good luck – ygngy Mar 09 '20 at 19:41

7 Answers7

5

To echieve this you need to make a SplashScreen.xml in the Layout folder in Android Project. Also you need to make the styles in two folders, values and values-night.

Also you need a separate SplashActivity.cs. I am attaching the code herewith.

  1. SplashScreen.xml

      <?xml version="1.0" encoding="utf-8"?>
      <RelativeLayout 
       xmlns:android="http://schemas.android.com/apk/res/android"
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       android:gravity="center_vertical" 
       android:background="#fff"
       android:id="@+id/splashview">
       <TextView
            android:id="@+id/txtAppVersion"
            android:text="Anki+"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_marginLeft="30dp"
            android:layout_marginBottom="30dp"
            android:textColor="#000"
            android:textSize="24sp"
            android:gravity="center_vertical" 
            android:layout_centerHorizontal="true"/>
        </RelativeLayout>
    
  2. Styles.xml in values folder.

    <style name="MainTheme" parent="MainTheme.Base">
        <item name="android:textAllCaps">false</item>
    </style>
    
    <style name="MainTheme.Base" parent="Theme.AppCompat.Light.DarkActionBar">
        <item name="windowNoTitle">true</item>
        <item name="windowActionBar">false</item>
        <item name="windowActionModeOverlay">true</item>
        <item name="elevation">0dp</item>
    </style>
    
    <style name="LaunchTheme" parent="Theme.AppCompat">
        <item name="android:windowNoTitle">true</item>
        <item name="android:windowActionBar">false</item>
        <item name="android:windowFullscreen">true</item>
        <item name="android:windowContentOverlay">@null</item>
        <item name="android:windowDisablePreview">true</item>
    </style>
    

  3. Styles.xml in values-night folder.

    <style name="MainTheme" parent="MainTheme.Base">
        <item name="android:textAllCaps">false</item>
    </style>
    
    <style name="MainTheme.Base" parent="Theme.AppCompat.Light.DarkActionBar">
        <item name="windowNoTitle">true</item>
        <item name="windowActionBar">false</item>
        <item name="windowActionModeOverlay">true</item>
        <item name="elevation">0dp</item>
    </style>
    
    <style name="LaunchTheme" parent="Theme.AppCompat">
        <item name="android:windowNoTitle">true</item>
        <item name="android:windowActionBar">false</item>
        <item name="android:windowFullscreen">true</item>
        <item name="android:windowContentOverlay">@null</item>
        <item name="android:windowDisablePreview">true</item>
    </style>
    

  4. SplashActivity.cs

    using System;
    using Android.App;
    using Android.Content;
    using Android.Content.Res;
    using Android.OS;
    using Android.Runtime;
    using Android.Views;
    using Android.Widget;
    using Plugin.CurrentActivity;
    
    namespace MyProject.Droid
    {
        [Activity(Label = "MyProject+", Theme = "@style/LaunchTheme", 
    MainLauncher = true, NoHistory = true)]
    public class SplashActivity : Activity
    {
    
        public override void OnCreate(Bundle savedInstanceState, PersistableBundle persistentState)
        {
            base.OnCreate(savedInstanceState, persistentState);
    
            //==================================== Code to hide the bottom 3 buttons on Android.
            int uiOptions = (int)Window.DecorView.SystemUiVisibility;
            uiOptions |= (int)SystemUiFlags.LowProfile;
            uiOptions |= (int)SystemUiFlags.Fullscreen;
            uiOptions |= (int)SystemUiFlags.HideNavigation;
            uiOptions |= (int)SystemUiFlags.ImmersiveSticky;
            Window.DecorView.SystemUiVisibility = (StatusBarVisibility)uiOptions;
            //===================================
    
            base.SetTheme(Resource.Style.MainTheme);
            Xamarin.Essentials.Platform.Init(this, savedInstanceState);
        }
    
        // Launches the startup task
        protected override void OnResume()
        {
            base.OnResume();
            SetContentView(Resource.Layout.SplashScreen);
            bool isDarkTheme;
    
            //var isDarkTheme = Preferences.Get("isDarkTheme", false);
            if (Build.VERSION.SdkInt >= BuildVersionCodes.Froyo)
            {
                var uiModeFlags = CrossCurrentActivity.Current.AppContext.Resources.Configuration.UiMode & UiMode.NightMask;
                if (uiModeFlags == UiMode.NightYes)
                    isDarkTheme = true;
                else isDarkTheme = false;
            }
            else
                isDarkTheme = false;
    
            if (isDarkTheme)
            {
                FindViewById<RelativeLayout>(Resource.Id.splashview).SetBackgroundColor(Android.Graphics.Color.ParseColor("#000000"));
                FindViewById<TextView>(Resource.Id.txtAppVersion).SetTextColor(Android.Graphics.Color.ParseColor("#FFFFFF"));
            }
            else
            {
                FindViewById<RelativeLayout>(Resource.Id.splashview).SetBackgroundColor(Android.Graphics.Color.ParseColor("#FFFFFF"));
                FindViewById<TextView>(Resource.Id.txtAppVersion).SetTextColor(Android.Graphics.Color.ParseColor("#000000"));
            }
    
            // FindViewById<TextView>(Resource.Id.txtAppVersion).Text = $"Version {PackageManager.GetPackageInfo(PackageName, 0).VersionName}";
    
            //==================================== Code to hide the bottom 3 buttons on Android.
            int uiOptions = (int)Window.DecorView.SystemUiVisibility;
            uiOptions |= (int)SystemUiFlags.LowProfile;
            uiOptions |= (int)SystemUiFlags.Fullscreen;
            uiOptions |= (int)SystemUiFlags.HideNavigation;
            uiOptions |= (int)SystemUiFlags.ImmersiveSticky;
            Window.DecorView.SystemUiVisibility = (StatusBarVisibility)uiOptions;
            //===================================
    
            System.Threading.Tasks.Task startupWork = new System.Threading.Tasks.Task(() => { SimulateStartup(); });
            startupWork.Start();
        }
    
        // Simulates background work that happens behind the splash screen
        async void SimulateStartup()
        {
            await System.Threading.Tasks.Task.Delay(1000); // Simulate a bit of startup work.
            StartActivity(new Intent(Application.Context, typeof(MainActivity)));
        }
    
        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);
        }
    
        public override void OnBackPressed() { }
    }
    }
    
halfer
  • 19,824
  • 17
  • 99
  • 186
Nikhil
  • 3,387
  • 1
  • 8
  • 16
3

Have you tried using a daynight theme? something like this in your style file

<style name="LaunchTheme" parent="Theme.AppCompat.DayNight">
<item name="android:windowBackground">@drawable/splash_screen</item>
<item name="android:navigationBarColor">#ffffff</item>
</style>

Let me know if it works!

Mateo Hervas
  • 545
  • 1
  • 5
  • 20
  • Thanks for that interesting suggestion. I have never heard of that theme. I don't really have any experience with Android xaml. Caan you show me how I could set up the text in the center of the page and the background also in the splash_screens using the sample Xaml. Then I can test it out and get back to you with this. Thanks – Alan2 Feb 29 '20 at 15:45
  • You could refer to this medium for guidance on how to set up the colors depending on day or night mode! https://medium.com/@daniel.nesfeder/android-how-to-set-up-custom-day-night-themes-in-your-app-2e5b8ac83277 – Mateo Hervas Feb 29 '20 at 17:41
  • I introduced a large bonus for this question. Letting you know in case you are interested in trying to come up with a working demo using your suggestion. – Alan2 Mar 02 '20 at 16:46
2

You don't actually need a SplashActivity. Just use a layerlist splash_screen.xml in your drawable folder. Set the Theme of your MainActivty to your SplashTheme and in the OnCreate of your MainActivity before your call base.OnCreate add the line SetTheme(Resource.Style.RealApplicationTheme) so that the real AppTheme then takes over.

Make sure your splash theme contains the following

<item name="android:windowBackground">@drawable/splash_screen</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowFullscreen">true</item>

This way your splash screen will stay on the screen for as long as the device takes to do a cold start. Therefore you don't need to be concerned about handling an extra activity and some artificial timeout. You can measure the display time just by searching for string "display" in the logs which will contain the actual time period of the cold start. Sub 1 sec display times are achievable.

Obviously, on later warm starts you hardly get to see the splash screen because the start time is much faster since your app is already in memory.

Once you get it right then enable startup tracing to make your startup time even faster.

user2153142
  • 431
  • 1
  • 4
  • 7
1

Create colors for background and foreground in two values folders under res folder:

  • values-night folder for night mode
  • values folder for day mode

for night mode in res/values-night/colors.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="splashForeground">#FFFFFF</color>
    <color name="splashBackground">#000000</color>
</resources>

for day mode in res/values/colors.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="splashForeground">#000000</color>
    <color name="splashBackground">#FFFFFF</color>
</resources>

in your layout for splash screen use the colors res/layout/splash.xml:

<?xml version="1.0" encoding="utf-8"?>
<TextView  xmlns:android="http://schemas.android.com/apk/res/android"
        android:text="ABC"
        android:textColor="@color/splashForeground"
        android:background="@color/splashBackground"

        android:gravity="center"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:textSize="24sp"
        />
ygngy
  • 3,630
  • 2
  • 18
  • 29
0

You can use this code for determining the device theme and based on that you can set text and color.

Sahil Doshi
  • 346
  • 1
  • 3
  • 13
0

Here are a few quotes from the Android Documentation Regarding Providing alternative resources.

Extra Info.

Night mode

night
notnight
  • night: Night time
  • notnight: Day time

Added in API level 8.

This can change during the life of your app if night mode is left in auto mode (default), in which case the mode changes based on the time of day. You can enable or disable this mode using UiModeManager. See Handling Runtime Changes for information about how this affects your app during runtime.


(I don't know if you already have done this steps since you have a style for each splash screen, but since you couldn't change the text color, i will include this steps anyways)

1º - Create 2 Drawable XML files

Create 2 drawable files called splash_screen.xml And splash_screen_night.xml:

<layer-list xmlns:android="http://schemas.android.com/apk/res/android" android:opacity="opaque">
    <item>
        <TextView
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          android:gravity="center"
          android:textColor="#00000"
          android:text="Text in Center" />
    </item>
</layer-list>

<layer-list xmlns:android="http://schemas.android.com/apk/res/android" android:opacity="opaque">
    <item>
        <TextView
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          android:gravity="center"
          android:textColor="#FFFFFF"
          android:text="Text in Center" />
    </item>
</layer-list>

2º - Create a Night Theme

Create a folder called values-night to implement the Dark Theme splash screen, and add to an existing folder called values to implement the Light Theme splash screen.

Note: Here is where the "magic" happens, Android will use values or values-night depending on the Device NightMode, notnight will do the same as night, but for DayMode

Inside the values-night folder, create an empty styles.xml file, and add the style to include the Dark Theme splash screen:

<resources>
    <style name="LaunchTheme" parent="Theme.AppCompat">
        <item name="android:windowBackground">@drawable/splash_screen_night</item>
    </style>
</resources>

And of course, in the values>style.xaml, the Ligth Theme splash screen

<style name="LaunchTheme" parent="MainTheme">
    <item name="android:windowBackground">@drawable/splash_screen</item>
</style>

3º Update the MainActivity.cs to use the new LauchTheme

Update MainActivity to ensure it uses the newly created LaunchTheme as the Splash Screen. Activity attribute to use the following values:

Theme = "@style/LaunchTheme"
LaunchMode = LaunchMode.SingleTop

E.G.:

[Activity(Label = "DarkModeSplashScreen", Icon = "@mipmap/icon", Theme = "@style/LaunchTheme", LaunchMode = LaunchMode.SingleTop, MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]

And then in the OnCreate method before base.OnCreate:

protected override void OnCreate(Bundle savedInstanceState)
{
    //...

    base.SetTheme(Resource.Style.MainTheme);
    base.OnCreate(savedInstanceState);

    //...
}
Ricardo Dias Morais
  • 1,947
  • 3
  • 18
  • 36
0

This is the simple and optimal solution to implement a Day / Night Theme for your app. Please follow the steps.

Step One: Change to DayNight Theme

Navigate to your styles.xml file and change your parent theme to DayNight

<style name="LaunchTheme" parent="Theme.AppCompat.DayNight">
    <!-- Theme attributes -->

</style>

This will enable your app to detect day & night configuration changes. Note: Just like other themes, this one also has its variations such as Theme.AppCompat.DayNight.NoActionBar

Step Two: Add attributes to your DayNight Theme

<style name="LaunchTheme" parent="Theme.AppCompat.DayNight.NoActionBar">

    <!-- Other attributes might be present here by default such as 'colorPrimary' -->

    <!-- These colors are going to be defined on next step -->
    <item name="android:textColor">@color/textColor</item>
    <item name="android:windowBackground">@color/windowBackgroundColor</item>
</style>

For this example we are using textColor and windowBackground attributes. textColor is the app-wide default color attribute for textviews and windowBackground is the default attribute for activity window backgrounds.

You may choose a different approach later based on your needs and your understanding of Themes & Styles.

Step Three: Define colors

Navigate to your colors.xml and add these colors.

<resources>
<color name="textColor">#000000</color>
<color name="windowBackgroundColor">#FFFFFF</color>
</resources>

Step Four: Create a night-qualifier colors file

How its done in Android Studio: Right click values folder -> New -> Values resource file, name your file 'colors' and add NightMode Qualifier to it.

This will, if not exists, create a 'values-night' folder and colors.xml in it.

If this approach is not possible in the IDE you are using for Xamarin development, please create the files manually: Under 'res' folder, create a 'values-night' folder. And then create 'colors.xml' file under 'values-night' folder.

Step Five: Define same colors in your NightMode qualified colors file

Navigate to newly created colors.xml file under 'values-night' folder and add these colors.

<resources>
<color name="textColor">#FFFFFF</color>
<color name="windowBackgroundColor">#000000</color>
</resources>

Notice that color resource names are same yet they have different values.

Step Six: Use the Theme

Set the Style you defined at Step One as your App-Wide Theme or as your Splash Activity Theme. ( You have already done this )

It is done, your application will now react to day-night configurations.

Testing

Run the project on a device with Android version >= Q and toggle the devices night mode on/off.

Or add these code to your Application class' onCreate function

AppCompatDelegate.setDefaultNightMode(
        AppCompatDelegate.MODE_NIGHT_YES); // This code will force night mode configuration for your app. Add it to see how your app looks in night mode.

AppCompatDelegate.setDefaultNightMode(
        AppCompatDelegate.MODE_NIGHT_NO); // This code will force day mode configuration for your app. Add it to see how your app looks in day mode.

Important: Make sure you are not overriding the intended visual result by, for example, setting a hard coded color value directly to your TextView.

Nezih Yılmaz
  • 626
  • 4
  • 8