Reputation: 869
I am writing an app which has both light and dark modes as declared here:
styles.xml
<style name="Noon" parent="Theme.AppCompat.NoActionBar">
<item name="upper_bg">@drawable/day_sky_top</item>
<item name="lower_bg">@drawable/day_sky</item>
<item name="android:statusBarColor">@color/colorPrimaryDark</item>
</style>
<style name="Night" parent="Theme.AppCompat.NoActionBar">
<item name="upper_bg">@drawable/night_sky_top</item>
<item name="lower_bg">@drawable/night_sky</item>
<item name="android:statusBarColor">@color/colorNightDark</item>
</style>
By following this answer, I created the following file:
/res/values/attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="customAttrs">
<attr name="upper_bg" format="reference" />
<attr name="lower_bg" format="reference" />
</declare-styleable>
</resources>
And customized my ImageViews like this:
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageView
android:id="@+id/top_bg"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="0.65"
android:src="?attr/upper_bg"/>
<ImageView
android:id="@+id/bottom_bg"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="0.35"
android:src="?attr/lower_bg"/>
</LinearLayout>
(Note that this is part of the code, all tags are properly closed.)
Everything works well provided I have:
boolean night = true;
setTheme(night ? R.style.Night : R.style.Noon);
setContentView(R.layout.activity_main); // or whatever activity I'm in.
on every single Activity of my app. Is there a way to run this code ONCE so that my theme changes globally?
Upvotes: 0
Views: 1227
Reputation: 661
You can still add a BaseActivity
to then override override fun onCreate()
, delegating it the responsibility of setTheme()
for any other Activity
that inherits from it.
override fun onCreate(savedInstanceState: Bundle?) {
val night = true
setTheme(if (night) R.style.Night else R.style.Noon)
}
if you don't prefer BaseActivity
, you can create an extension function somewhere in charged of set theme according user preferences:
fun Activity.setTheme() {
val night = true
// Or even have more than two theme styles
this.setTheme(if (night) R.style.Night else R.style.Noon)
}
To then be called like this:
override fun onCreate(savedInstanceState: Bundle?) {
setTheme()
}
UPDATE: Java code
This class would be your base class for each required Activity
public abstract class BaseActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
boolean night = true;
setTheme(night ? R.style.Night : R.style.Noon);
}
}
So now, imagine you have to implement "Feature 1" and "Feature 2", so that, you just inherits them from BaseActivity
.
"Feature 1":
public class Feature1Activity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); // <- BaseActivity's onCreate() will set theme for you
setContentView(R.layout.activity_feature_1);
}
}
"Feature 2":
public class Feature2Activity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); // <- BaseActivity's onCreate() will set theme for you
setContentView(R.layout.activity_feature_2);
}
}
Upvotes: 1
Reputation: 606
Yes you can ! You have to use method setDefaultNightMode() of class AppCompatDelegate that take the value of the theme you want to apply , the values available is MODE_NIGHT_NO & MODE_NIGHT_YES & MODE_NIGHT_FOLLOW_SYSTEM for light , night and phone default theme respectively , you can do something like this :
AppCompatDelegate.setDefaultNightMode(THE_MODE_YOU_WANT);
Its important to note that starting with AppCompat v1.0.0 , when this method get called it recreates all running activity to apply the theme .
If you are running Api 29 or higher , you should consider using Force Dark , you can check it all in the official document to get better understanding of it .
Enjoy !
Upvotes: 0