In my Xamarin Forms Android app, I would like to change the color of the splash screen based on a theme that the user has selected at run time. This change should impact the next run of the app.
I have tried using the built in splash_screen.xml and using a Splash.axml file, but I cannot figure out how (if possible) to set the background color of the splash screen to a color defined in a theme.
Is this possible?
I have tried using the built in splash_screen.xml and using a Splash.axml file, but I cannot figure out how (if possible) to set the background color of the splash screen to a color defined in a theme.
You can define themes for your splashScreen and then set android:windowBackground to a specific color:
styles.xml:
<resources>
<style name="AppTheme">
<item name="android:windowBackground">#color/colorPrimary</item>
<item name="android:windowNoTitle">true</item>
</style>
<style name="AppTheme2">
<item name="android:windowBackground">#color/colorAccent</item>
<item name="android:windowNoTitle">true</item>
</style>
...
</resources>
SplashScreen.cs( don't forget to set SplashScreen activity to be mainlauncher):
[Activity(Label = "SplashActivity",MainLauncher =true)]
public class SplashActivity : Activity
{
protected override void OnCreate(Bundle savedInstanceState)
{
ISharedPreferences preferences=GetSharedPreferences("SplashThemeId", FileCreationMode.Private);
var themeName=preferences.GetString("themeName","AppTheme");
int themeId = Resource.Style.AppTheme ;
switch (themeName)
{
case "AppTheme":
themeId = Resource.Style.AppTheme;
break;
case "AppTheme2":
themeId = Resource.Style.AppTheme2;
break;
}
SetTheme(themeId);
base.OnCreate(savedInstanceState);
...
As you noticed, I use SharedPreference to store the user selected Theme in Runtime. You can also use Android Settings for the same purpose.
Here is the complete demo. It's native android project, but it's the same for forms project.
After all of the research I've done and the things I've tried in code, I am concluding that it is not possible to dynamically set the color of the initial activity. I am going with a neutral color for the splash.
Related
I'm using React Native for building my android application and I've followed this tutorial to set up my splash screen. Here is the result. My main problem is that the status bar color changes to black, I can't solve this by having <item name="colorPrimaryDark">#color/colorPrimaryDark</item> in my styles.xml file, and <color name="blue">#009CD7</color>, <color name="colorPrimaryDark">#009CD7</color> in my colors.xml file.
Bonus question: how to center the image without hardcoding a margin so that it stays in the center regardless of the device the app is running on?
Add colorPrimaryDark one more item in your current splash theme or create a new one.
<style name="SplashTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="android:statusBarColor">#android:color/white</item>
<item name="android:windowLightStatusBar">true</item>
<item name="android:background">#drawable/background_splash</item>
<item name="colorPrimaryDark">#android:color/white</item>
</style>
Then use it as a second parameter while showing SplashScreen.
public class MainActivity extends ReactActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
SplashScreen.show(this, R.style.SplashTheme, true);
super.onCreate(savedInstanceState);
}
}
If you see an error something like that -> "int can not be boolean"
Just add third parameter to MainActivity.java
SplashScreen.show(this, R.style.SplashTheme, true);
Create a style definition for this in android/app/src/main/res/values/styles.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="SplashTheme" parent="SplashScreen_SplashTheme">
<item name="colorPrimaryDark">your_color</item>
</style>
</resources>
now you have change show method to include your custom style:
SplashScreen.show(this, R.style.SplashTheme);
you are donw now :)
If you wanna change the TaskBar color, just add the activity and the color that you desire in the output function.
fun setTaskBarColored(colored: Int,activity: Activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
activity.window!!.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
activity.window!!.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
activity.window!!.statusBarColor = ContextCompat.getColor(activity, colored)
}
}
And also the same applies for the NavigationBar
fun setNavigationBarColored(colored: Int, activity: Activity){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
activity.window!!.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
activity.window!!.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
activity.window!!.navigationBarColor = ContextCompat.getColor(activity, colored)
}
}
You can simply add this JSX code to the root of your app instead of editing any native files.
<StatusBar backgroundColor="blue" barStyle="light-content" />
Also in order to center your image, wrap it with a view and add the styling “{justifyContent: ‘center’, alignItems: ‘center’}”. If that doesn’t work then add this style directly to your image component “alignSelf: ‘center’”
Is it possible if my theme values are downloadable from server then my mobile theme will change according to what I specify from it?
Example if I have columns [colorPrimary] and [colorAccent] from server then after downloading values, my app theme colors will change accordingly.
This is my current theme.
<style name="Base.Theme.Design" parent="Theme.AppCompat.Light.NoActionBar">
<item name="colorPrimary">#013034</item>
<item name="colorPrimaryDark">#013034</item>
<item name="colorAccent">#1490a0</item>
<item name="android:textColorHint">#9e9e9e</item>
</style>
Note: For all downvotes, please leave comment for improvement of this post. Thanks.
You can use Firebase remote config to apply that, for example if you have multiple theme options for your app like "Base.Theme.Design_A" and "Base.Theme.Design_B" which are already built-in your app. You can switch between and apply one of these themes by checking a remote property in Firebase remote config. Also you can change old value and fetch the remote values and activate them (not with style file)
<defaultsMap>
<entry>
<!-- color entries -->
<entry>
<key>colorPrimary</key>
<value>#013034</value>
</entry>
<entry>
<key>colorPrimaryDark</key>
<value>#013034</value>
</entry>
To change your app's colour dynamically, for elaborate implementations refer to this
There is a way to change your App's theme dynamically.
You need put two the themes in your styles.xml in advance, like this:
<style name="AppThemeA" parent="Theme.AppCompat.Light.NoActionBar">
<item name="colorPrimary">#aba424</item>
<item name="colorPrimaryDark">#9f2020</item>
<item name="colorAccent">#2a6c29</item>
</style>
<style name="AppThemeB" parent="Theme.AppCompat.Light.NoActionBar">
<item name="colorPrimary">#706464</item>
<item name="colorPrimaryDark">#831444</item>
<item name="colorAccent">#183150</item>
</style>
And use one of them in your codes.
For example, there is button in your MainActivity, if you click it, your theme will change to AppThemeA, so you need do this in your MainActivity's OnCreate:
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
if ("A".Equals(Intent.GetStringExtra("Theme")))
{
SetTheme(Resource.Style.AppThemeA);
}
else if("B".Equals(Intent.GetStringExtra("Theme"))) {
SetTheme(Resource.Style.AppThemeB);
}
SetContentView(Resource.Layout.Main);
Button button = FindViewById<Button>(Resource.Id.bt);
button.Click += (sender, e) => {
Intent intent= new Intent(this, typeof(MainActivity));
intent.PutExtra("Theme","A");
StartActivity(intent);
Finish();
};
}
I have made a few apps that support multiple themes, but I always had to restart the app when user switches theme, because setTheme() needs to be called before setContentView().
I was okay with it, until I discovered this app. It can seamlessly switch between two themes, and with transitions/animations too!
Please give me some hints on how this was implemented (and animations too). Thanks!
#Alexander Hanssen's answer basically has answered this...
Don't know why it was not accepted... Maybe because of the finish()/startActivity().
I voted for it and I tried to comment but cannot...
Anyway, I would do exactly what he described in terms of styles.
<style name="AppThemeLight" parent="Theme.AppCompat.Light">
<!-- Customize your theme here. -->
<item name="android:windowAnimationStyle">#style/WindowAnimationTransition</item>
</style>
<style name="AppThemeDark" parent="Theme.AppCompat">
<!-- Customize your theme here. -->
<item name="android:windowAnimationStyle">#style/WindowAnimationTransition</item>
</style>
<!-- This will set the fade in animation on all your activities by default -->
<style name="WindowAnimationTransition">
<item name="android:windowEnterAnimation">#android:anim/fade_in</item>
<item name="android:windowExitAnimation">#android:anim/fade_out</item>
</style>
But instead of finish/start with new intent:
Intent intent = new Intent(this, <yourclass>.class);
startActivity(intent);
finish();
I would do:
#Override
protected void onCreate(Bundle savedInstanceState) {
// MUST do this before super call or setContentView(...)
// pick which theme DAY or NIGHT from settings
setTheme(someSettings.get(PREFFERED_THEME) ? R.style.AppThemeLight : R.style.AppThemeDark);
super.onCreate(savedInstanceState);
}
// Somewhere in your activity where the button switches the theme
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// decide which theme to use DAY or NIGHT and save it
someSettings.save(PREFFERED_THEME, isDay());
Activity.this.recreate();
}
});
The effect is as shown in the video...
The transition/animation makes the theme change seamless when you restart the activity, and this can be done by adding the items "android:windowanimationStyle" to your themes, and then referencing a style where you specifiy how the Activity should animate when it enters and exits.
Note that this makes the animation apply on all activities with that theme.
<style name="AppThemeLight" parent="Theme.AppCompat.Light">
<!-- Customize your theme here. -->
<item name="android:windowAnimationStyle">#style/WindowAnimationTransition</item>
</style>
<style name="AppThemeDark" parent="Theme.AppCompat">
<!-- Customize your theme here. -->
<item name="android:windowAnimationStyle">#style/WindowAnimationTransition</item>
</style>
<!-- This will set the fade in animation on all your activities by default -->
<style name="WindowAnimationTransition">
<item name="android:windowEnterAnimation">#android:anim/fade_in</item>
<item name="android:windowExitAnimation">#android:anim/fade_out</item>
</style>
Then, when you want to change theme you could do this when clicking a button:
AppSettings settings = AppSettings.getInstance(this);
settings.set(AppSettings.Key.USE_DARK_THEME,
!settings.getBoolean(AppSettings.Key.USE_DARK_THEME));
Intent intent = new Intent(this, <yourclass>.class);
startActivity(intent);
finish();
Then in your onCreate method, use the setTheme() to apply the theme that is currently set in AppSettings like this:
AppSettings settings = AppSettings.getInstance(this);
setTheme(settings.getBoolean(AppSettings.Key.USE_DARK_THEME) ? R.style.AppThemeDark : R.style.AppThemeLight);
super.onCreate(savedInstanceState);
setContentView(<yourlayouthere>);
Check out this gist for reference: https://gist.github.com/alphamu/f2469c28e17b24114fe5
for those who are trying to find solution for android version 10 or updated.
to set dark/light mode use this:
AppCompatDelegate.setDefaultNightMode(state) //state can be AppCompatDelegate.MODE_NIGHT_YES or AppCompatDelegate.MODE_NIGHT_NO
it will change the display of your app but with a flicker
to avoid the activity recreation flicker (for smooth transition), in your activity add the below method
#Override
public void recreate() {
finish();
overridePendingTransition(R.anim.anime_fade_in,
R.anim.anime_fade_out);
startActivity(getIntent());
overridePendingTransition(R.anim.anime_fade_in,
R.anim.anime_fade_out);
}
setTheme() before super.onCreate(savedInstanceState) in GKA answer is perfect approach and work well, thanks to GKA.
but it creates new instances for all resources again, including activities, fragments, and recycler views. I think it may be heavy work and cause to loss of some saved data like local variables.
accourding to google document: https://developer.android.com/reference/android/app/Activity#recreate()
Cause this Activity to be recreated with a new instance. This results
in essentially the same flow as when the Activity is created due to a
configuration change -- the current instance will go through its
lifecycle to onDestroy() and a new instance then created after it.
there is another approach that you can change the theme programmatically with code (Java or Kotlin), in this approach you don't need to recreate all resources, and also you can use custom animation like ripple.
check my GitHub library:
https://github.com/imandolatkia/Android-Animated-Theme-Manager
in this library, you can create your custom themes and change them dynamically with ripple animation without recreating any resources.
Simply efficient one liner in fragment:
requireActivity().recreate();
For activity:
recreate();
There isn't anything preventing you from calling setTheme() and then setContentView() again. You'll just need to restructure your app a bit so that, if you change the theme, you need to reinitialize any member variables you might have that are holding references to View objects.
I need to run a custom dialog layout using only theme/style options. Running custom Dialog layout by code is not an option for me. I think this should be possible by mean of attributes "android:layout", "android:dialogLayout", "*android:dialogCustomTitleDecorLayout", "*android:dialogTitleIconsDecorLayout", "*android:dialogTitleDecorLayout".<br/><br/>
My Activity onCreate load layout in a Dialog Style:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setTheme(R.style.MyDialog);
setContentView(R.layout.mydialog);
this.setTitle("A title");
}
style xml:
<style name="MyDialog" parent="android:Theme.Holo.Light.Dialog">
<item name="android:windowTitleStyle">#style/MyDialog.WindowTitle</item>
<item name="android:layout">#layout/dialog_title</item>
<item name="android:dialogLayout">#layout/dialog_title</item>
<item name="*android:dialogCustomTitleDecorLayout">#layout/dialog_title</item>
<item name="*android:dialogTitleIconsDecorLayout">#layout/dialog_title</item>
<item name="*android:dialogTitleDecorLayout">#layout/dialog_title</item>
</style>
<style name="MyDialog.WindowTitle">
<item name="android:maxLines">1</item>
<item name="android:scrollHorizontally">true</item>
<item name="android:textAppearance">#style/TextAppearance_WindowTitle</item>
</style>
<style name="TextAppearance_WindowTitle">
<item name="android:textSize">32sp</item>
<item name="android:textColor">#+color/verdeTI</item>
</style>
Please, note that Text colour of the title is correctly applied (#+color/verdeTI) so I am confident the cascading styling is right but it seems none of the layout options work at all because I continue to see the standard Dialog Layout. My "dialog_title" use a completely different ImageView for divider so I can be sure when it is loaded.
The custom divider is just the main reason because I need a different layout.
Update 15/4/2014
Android theme Guide stats:
Some style properties, however, are not supported by any View element and can only be applied as a theme. These style properties apply to the entire window and not to any type of View. For example, style properties for a theme can hide the application title, hide the status bar, or change the window's background. These kind of style properties do not belong to any View object. To discover these theme-only style properties, look at the R.attr reference for attributes that begin with window. For instance, windowNoTitle and windowBackground are style properties that are effective only when the style is applied as a theme to an Activity or application. See the next section for information about applying a style as a theme.
OK attributes starting with "window" are applied only in Themes not in Styles. What's about *Layout attributes ? When they are applied ?
You can try by passing ThemeName as argument of constructor like this way.
public class TestDialog extends Dialog{
public TestDialog(Context context) {
super(context, R.style.YourTheme);
// TODO Auto-generated constructor stub
}
}
Add window feature if you require.
Make object of this class in any Activity so you can use Dialog property.
:-
More info https://stackoverflow.com/a/18224754/942224
i was using this way. so it may be help you.
You can try by creating your required layout file and opening it with an activity class just in the manifest add this code to your activity
android:theme="#android:style/Theme. Dialog"
But you will be getting title bar in your dialog with this which is your label name for your activity. To remove it add this code before setContentView
requestWindowFeature(Window. FEATURE_NO_TITLE);
Currently, I'm using this to show my application background as phone wallpaper.
getWindow().setFlags(WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER,
WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER);
But for some reason when I start my application by pressing the icon. It just shows the activity screen with the icons on the home screen. I didn't use dialog but it looks like a dialog because layout is just set that way. So I just want to show the wallpaper whenever this activity is running. But it only shows the wallpaper only after the next event occurs such as switching to different activity. I already put that code on onCreate() and whenever I do setContentView()..... Is there way to do such thing or there is just no way?
For users of AppCompat, just use the following in your styles.xml, no need for code:
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat">
<item name="android:windowBackground">#android:color/transparent</item>
<item name="android:colorBackgroundCacheHint">#null</item>
<item name="android:windowShowWallpaper">true</item>
<item name="android:windowTranslucentNavigation">true</item>
<item name="android:windowTranslucentStatus">true</item>
</style>
After long search and trial and error. I've found the solution to what I wanted. It was just creating separate themes.xml file and just tweak the Theme.Dialog which is already defined in default android themes.xml. All I did was change the Animation part. Originally in android themes.xml the line looks like this.
<item name="android:windowAnimationStyle">#android:style/Animation.Dialog</item>
but since modifying in android themes.xml doesn't take the effect. I just created my own themes.xml as I said above and just set parent as android:Theme.Dialog. And added a line like this.
<item name="android:windowAnimationStyle">#android:style/Animation</item>
Thanks for the help and I hope this solution helps others.
Use following code -
rl = (RelativeLayout)findViewById(R.id.someid);
//relative layout is my root node in main.xml (yours may be linearlayout)
WallpaperManager wm = WallpaperManager.getInstance(this);
Drawable d = wm.peekDrawable();
rl.setBackgroundDrawable(d);// You can also use rl.setBackgroundDrawable(getWallpaper);