计算器怎么调钢琴模式是夜间模式怎样调日间模式

Android实现日夜间模式的深入理解
转载 &更新时间:日 08:47:21 & 投稿:daisy
相信Android的日间/夜间模式切换相信大家在平时使用 APP 的过程中都遇到过,比如知乎、简书中就有相关的模式切换。实现日间/夜间模式切换的方案也有许多种,趁着今天有空来讲一下日间/夜间模式切换的几种实现方案,也可以做一个横向的对比来看看哪种方案最好。
在本篇文章中给出了三种实现日间/夜间模式切换的方案,三种方案综合起来可能导致文章的篇幅过长,请耐心阅读。
&&& 1、使用 setTheme 的方法让 Activity 重新设置主题;
&&& 2、设置 Android Support Library 中的 UiMode 来支持日间/夜间模式的切换;
&&& 3、通过资源 id 映射,回调自定义 ThemeChangeListener 接口来处理日间/夜间模式的切换。
一、使用 setTheme 方法
我们先来看看使用 setTheme 方法来实现日间/夜间模式切换的方案。这种方案的思路很简单,就是在用户选择夜间模式时,Activity 设置成夜间模式的主题,之后再让 Activity 调用 recreate() 方法重新创建一遍就行了。
那就动手吧,在 colors.xml 中定义两组颜色,分别表示日间和夜间的主题色:
&?xml version="1.0" encoding="utf-8"?&
&resources&
&color name="colorPrimary"&#3F51B5&/color&
&color name="colorPrimaryDark"&#303F9F&/color&
&color name="colorAccent"&#FF4081&/color&
&color name="nightColorPrimary"&#3b3b3b&/color&
&color name="nightColorPrimaryDark"&#383838&/color&
&color name="nightColorAccent"&#a72b55&/color&
&/resources&
之后在 styles.xml 中定义两组主题,也就是日间主题和夜间主题:
&resources&
&!-- Base application theme. --&
&style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"&
&!-- Customize your theme here. --&
&item name="colorPrimary"&@color/colorPrimary&/item&
&item name="colorPrimaryDark"&@color/colorPrimaryDark&/item&
&item name="colorAccent"&@color/colorAccent&/item&
&item name="android:textColor"&@android:color/black&/item&
&item name="mainBackground"&@android:color/white&/item&
&style name="NightAppTheme" parent="Theme.AppCompat.Light.DarkActionBar"&
&!-- Customize your theme here. --&
&item name="colorPrimary"&@color/nightColorPrimary&/item&
&item name="colorPrimaryDark"&@color/nightColorPrimaryDark&/item&
&item name="colorAccent"&@color/nightColorAccent&/item&
&item name="android:textColor"&@android:color/white&/item&
&item name="mainBackground"&@color/nightColorPrimaryDark&/item&
&/resources&
在主题中的 mainBackground 属性是我们自定义的属性,用来表示背景色:
&?xml version="1.0" encoding="utf-8"?&
&resources&
&attr name="mainBackground" format="color|reference"&&/attr&
&/resources&
接下来就是看一下布局 activity_main.xml:
&?xml version="1.0" encoding="utf-8"?&
&RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/mainBackground"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.yuqirong.themedemo.MainActivity"&
android:id="@+id/btn_theme"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="切换日/夜间模式" /&
android:id="@+id/tv"
android:layout_below="@id/btn_theme"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:text="通过setTheme()的方法" /&
&/RelativeLayout&
在 &RelativeLayout& 的 android:background 属性中,我们使用 "?attr/mainBackground" 来表示,这样就代表着 RelativeLayout 的背景色会去引用在主题中事先定义好的 mainBackground 属性的值。这样就实现了日间/夜间模式切换的换色了。
最后就是 MainActivity 的代码:
public class MainActivity extends AppCompatActivity {
// 默认是日间模式
private int theme = R.style.AppT
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 判断是否有主题存储
if(savedInstanceState != null){
theme = savedInstanceState.getInt("theme");
setTheme(theme);
setContentView(R.layout.activity_main);
Button btn_theme = (Button) findViewById(R.id.btn_theme);
btn_theme.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
theme = (theme == R.style.AppTheme) ? R.style.NightAppTheme : R.style.AppT
MainActivity.this.recreate();
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("theme", theme);
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
theme = savedInstanceState.getInt("theme");
在 MainActivity 中有几点要注意一下:
&&&& 1、调用 recreate() 方法后 Activity 的生命周期会调用 onSaveInstanceState(Bundle outState) 来备份相关的数据,之后也会调用 onRestoreInstanceState(Bundle savedInstanceState) 来还原相关的数据,因此我们把 theme 的值保存进去,以便 Activity 重新创建后使用。
&&&& 2、我们在 onCreate(Bundle savedInstanceState) 方法中还原得到了 theme 值后,setTheme() 方法一定要在 setContentView() 方法之前调用,否则的话就看不到效果了。
&&&& 3、recreate() 方法是在 API 11 中添加进来的,所以在 Android 2.X 中使用会抛异常。
贴完上面的代码之后,我们来看一下该方案实现的效果图:
二、使用 Android Support Library 中的 UiMode 方法
使用 UiMode 的方法也很简单,我们需要把 colors.xml 定义为日间/夜间两种。之后根据不同的模式会去选择不同的 colors.xml 。在 Activity 调用 recreate() 之后,就实现了切换日/夜间模式的功能。
说了这么多,直接上代码。下面是 values/colors.xml :
&?xml version="1.0" encoding="utf-8"?&
&resources&
&color name="colorPrimary"&#3F51B5&/color&
&color name="colorPrimaryDark"&#303F9F&/color&
&color name="colorAccent"&#FF4081&/color&
&color name="textColor"&#FF000000&/color&
&color name="backgroundColor"&#FFFFFF&/color&
&/resources&
除了 values/colors.xml 之外,我们还要创建一个 values-night/colors.xml 文件,用来设置夜间模式的颜色,其中 &color& 的 name 必须要和 values/colors.xml 中的相对应:
&?xml version="1.0" encoding="utf-8"?&
&resources&
&color name="colorPrimary"&#3b3b3b&/color&
&color name="colorPrimaryDark"&#383838&/color&
&color name="colorAccent"&#a72b55&/color&
&color name="textColor"&#FFFFFF&/color&
&color name="backgroundColor"&#3b3b3b&/color&
&/resources&
在 styles.xml 中去引用我们在 colors.xml 中定义好的颜色:
&resources&
&!-- Base application theme. --&
&style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"&
&!-- Customize your theme here. --&
&item name="colorPrimary"&@color/colorPrimary&/item&
&item name="colorPrimaryDark"&@color/colorPrimaryDark&/item&
&item name="colorAccent"&@color/colorAccent&/item&
&item name="android:textColor"&@color/textColor&/item&
&item name="mainBackground"&@color/backgroundColor&/item&
&/resources&
activity_main.xml 布局的内容和上面 setTheme() 方法中的相差无几,这里就不贴出来了。之后的事情就变得很简单了,在 MyApplication 中先选择一个默认的 Mode :
public class MyApplication extends Application {
public void onCreate() {
super.onCreate();
// 默认设置为日间模式
AppCompatDelegate.setDefaultNightMode(
AppCompatDelegate.MODE_NIGHT_NO);
要注意的是,这里的 Mode 有四种类型可以选择:
&&& 1、MODE_NIGHT_NO: 使用亮色(light)主题,不使用夜间模式;
&&& 2、MODE_NIGHT_YES:使用暗色(dark)主题,使用夜间模式;
&&& 3、MODE_NIGHT_AUTO:根据当前时间自动切换 亮色(light)/暗色(dark)主题;
&&& 4、MODE_NIGHT_FOLLOW_SYSTEM(默认选项):设置为跟随系统,通常为 MODE_NIGHT_NO
当用户点击按钮切换日/夜间时,重新去设置相应的 Mode :
public class MainActivity extends AppCompatActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btn_theme = (Button) findViewById(R.id.btn_theme);
btn_theme.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
int currentNightMode = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
getDelegate().setLocalNightMode(currentNightMode == Configuration.UI_MODE_NIGHT_NO
? AppCompatDelegate.MODE_NIGHT_YES : AppCompatDelegate.MODE_NIGHT_NO);
// 同样需要调用recreate方法使之生效
recreate();
我们来看一下 UiMode 方案实现的效果图:
就前两种方法而言,配置比较简单,最后的实现效果也都基本上是一样的。但是缺点就是需要调用 recreate() 使之生效。而让 Activity 重新创建就必须涉及到一些状态的保存。这就增加了一些难度。所以,我们一起来看看第三种解决方法。
通过资源 id 映射,回调接口
第三种方法的思路就是根据设置的主题去动态地获取资源 id 的映射,然后使用回调接口的方式让 UI 去设置相关的属性值。我们在这里先规定一下:夜间模式的资源在命名上都要加上后缀 “_night” ,比如日间模式的背景色命名为 color_background ,那么相对应的夜间模式的背景资源就要命名为 color_background_night 。好了,下面就是我们的 Demo 所需要用到的 colors.xml :
&?xml version="1.0" encoding="utf-8"?&
&resources&
&color name="colorPrimary"&#3F51B5&/color&
&color name="colorPrimary_night"&#3b3b3b&/color&
&color name="colorPrimaryDark"&#303F9F&/color&
&color name="colorPrimaryDark_night"&#383838&/color&
&color name="colorAccent"&#FF4081&/color&
&color name="colorAccent_night"&#a72b55&/color&
&color name="textColor"&#FF000000&/color&
&color name="textColor_night"&#FFFFFF&/color&
&color name="backgroundColor"&#FFFFFF&/color&
&color name="backgroundColor_night"&#3b3b3b&/color&
&/resources&
可以看到每一项 color 都会有对应的 “_night” 与之匹配。
看到这里,肯定有人会问,为什么要设置对应的 “_night” ?到底是通过什么方式来设置日/夜间模式的呢?下面就由 ThemeManager 来为你解答:
public class ThemeManager {
// 默认是日间模式
private static ThemeMode mThemeMode = ThemeMode.DAY;
// 主题模式监听器
private static List&OnThemeChangeListener& mThemeChangeListenerList = new LinkedList&&();
// 夜间资源的缓存,key : 资源类型, 值&key:资源名称, value:int值&
private static HashMap&String, HashMap&String, Integer&& sCachedNightResrouces = new HashMap&&();
// 夜间模式资源的后缀,比如日件模式资源名为:R.color.activity_bg, 那么夜间模式就为 :R.color.activity_bg_night
private static final String RESOURCE_SUFFIX = "_night";
* 主题模式,分为日间模式和夜间模式
public enum ThemeMode {
DAY, NIGHT
* 设置主题模式
* @param themeMode
public static void setThemeMode(ThemeMode themeMode) {
if (mThemeMode != themeMode) {
mThemeMode = themeM
if (mThemeChangeListenerList.size() & 0) {
for (OnThemeChangeListener listener : mThemeChangeListenerList) {
listener.onThemeChanged();
* 根据传入的日间模式的resId得到相应主题的resId,注意:必须是日间模式的resId
* @param dayResId 日间模式的resId
* @return 相应主题的resId,若为日间模式,则得到dayResId;反之夜间模式得到nightResId
public static int getCurrentThemeRes(Context context, int dayResId) {
if (getThemeMode() == ThemeMode.DAY) {
return dayResId;
String entryName = context.getResources().getResourceEntryName(dayResId);
// 资源类型
String typeName = context.getResources().getResourceTypeName(dayResId);
HashMap&String, Integer& cachedRes = sCachedNightResrouces.get(typeName);
// 先从缓存中去取,如果有直接返回该id
if (cachedRes == null) {
cachedRes = new HashMap&&();
Integer resId = cachedRes.get(entryName + RESOURCE_SUFFIX);
if (resId != null && resId != 0) {
return resId;
//如果缓存中没有再根据资源id去动态获取
// 通过资源名,资源类型,包名得到资源int值
int nightResId = context.getResources().getIdentifier(entryName + RESOURCE_SUFFIX, typeName, context.getPackageName());
// 放入缓存中
cachedRes.put(entryName + RESOURCE_SUFFIX, nightResId);
sCachedNightResrouces.put(typeName, cachedRes);
return nightResId;
} catch (Resources.NotFoundException e) {
e.printStackTrace();
* 注册ThemeChangeListener
* @param listener
public static void registerThemeChangeListener(OnThemeChangeListener listener) {
if (!mThemeChangeListenerList.contains(listener)) {
mThemeChangeListenerList.add(listener);
* 反注册ThemeChangeListener
* @param listener
public static void unregisterThemeChangeListener(OnThemeChangeListener listener) {
if (mThemeChangeListenerList.contains(listener)) {
mThemeChangeListenerList.remove(listener);
* 得到主题模式
public static ThemeMode getThemeMode() {
return mThemeM
* 主题模式切换监听器
public interface OnThemeChangeListener {
* 主题切换时回调
void onThemeChanged();
上面 ThemeManager 的代码基本上都有注释,想要看懂并不困难。其中最核心的就是 getCurrentThemeRes 方法了。在这里解释一下 getCurrentThemeRes 的逻辑。参数中的 dayResId 是日间模式的资源id,如果当前主题是日间模式的话,就直接返回 dayResId 。反之当前主题为夜间模式的话,先根据 dayResId 得到资源名称和资源类型。比如现在有一个资源为 R.color.colorPrimary ,那么资源名称就是 colorPrimary ,资源类型就是 color 。然后根据资源类型和资源名称去获取缓存。如果没有缓存,那么就要动态获取资源了。这里使用方法的是
context.getResources().getIdentifier(String name, String defType, String defPackage)
name 参数就是资源名称,不过要注意的是这里的资源名称还要加上后缀 “_night” ,也就是上面在 colors.xml 中定义的名称;
defType 参数就是资源的类型了。比如 color,drawable等;
defPackage 就是资源文件的包名,也就是当前 APP 的包名。
有了上面的这个方法,就可以通过 R.color.colorPrimary 资源找到对应的 R.color.colorPrimary_night 资源了。最后还要把找到的夜间模式资源加入到缓存中。这样的话以后就直接去缓存中读取,而不用再次去动态查找资源 id 了。
ThemeManager 中剩下的代码应该都是比较简单的,相信大家都可以看得懂了。
现在我们来看看 MainActivity 的代码:
public class MainActivity extends AppCompatActivity implements ThemeManager.OnThemeChangeListener {
private TextV
private Button btn_
private RelativeLayout relativeL
private ActionBar supportActionB
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ThemeManager.registerThemeChangeListener(this);
supportActionBar = getSupportActionBar();
btn_theme = (Button) findViewById(R.id.btn_theme);
relativeLayout = (RelativeLayout) findViewById(R.id.relativeLayout);
tv = (TextView) findViewById(R.id.tv);
btn_theme.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
ThemeManager.setThemeMode(ThemeManager.getThemeMode() == ThemeManager.ThemeMode.DAY
? ThemeManager.ThemeMode.NIGHT : ThemeManager.ThemeMode.DAY);
public void initTheme() {
tv.setTextColor(getResources().getColor(ThemeManager.getCurrentThemeRes(MainActivity.this, R.color.textColor)));
btn_theme.setTextColor(getResources().getColor(ThemeManager.getCurrentThemeRes(MainActivity.this, R.color.textColor)));
relativeLayout.setBackgroundColor(getResources().getColor(ThemeManager.getCurrentThemeRes(MainActivity.this, R.color.backgroundColor)));
// 设置标题栏颜色
if(supportActionBar != null){
supportActionBar.setBackgroundDrawable(new ColorDrawable(getResources().getColor(ThemeManager.getCurrentThemeRes(MainActivity.this, R.color.colorPrimary))));
// 设置状态栏颜色
if (Build.VERSION.SDK_INT &= Build.VERSION_CODES.LOLLIPOP) {
Window window = getWindow();
window.setStatusBarColor(getResources().getColor(ThemeManager.getCurrentThemeRes(MainActivity.this, R.color.colorPrimary)));
public void onThemeChanged() {
initTheme();
protected void onDestroy() {
super.onDestroy();
ThemeManager.unregisterThemeChangeListener(this);
在 MainActivity 中实现了 OnThemeChangeListener 接口,这样就可以在主题改变的时候执行回调方法。然后在 initTheme() 中去重新设置 UI 的相关颜色属性值。还有别忘了要在 onDestroy() 中移除 ThemeChangeListener 。
最后就来看看第三种方法的效果吧:
也许有人会说和前两种方法的效果没什么差异啊,但是仔细看就会发现前面两种方法在切换模式的瞬间会有短暂黑屏现象存在,而第三种方法没有。这是因为前两种方法都要调用 recreate() 。而第三种方法不需要 Activity 重新创建,使用回调的方法来实现。
三个方法对比
到了这里,按照套路应该是要总结的时候了。那么就根据上面给的三种方法来一个简单的对比吧:
setTheme 方法:可以配置多套主题,比较容易上手。除了日/夜间模式之外,还可以有其他五颜六色的主题。但是需要调用 recreate() ,切换瞬间会有黑屏闪现的现象;
UiMode 方法:优点就是 Android Support Library 中已经支持,简单规范。但是也需要调用 recreate() ,存在黑屏闪现的现象;
动态获取资源 id ,回调接口:该方法使用起来比前两个方法复杂,另外在回调的方法中需要设置每一项 UI 相关的属性值。但是不需要调用 recreate() ,没有黑屏闪现的现象。
以上就是这篇文章的全部内容了,希望能对各位Android开发者们有所帮助。
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具关于日间夜间模式切换的一种实用方法
日夜间模式切换:
* 第一种设置夜间模式:通过重新给Activity设置主题,然后杀掉Activity,再创建Activity重新设置的之塔才 * 有效
* 搭建环境
* 1.在values中colors里设置颜色属性
* 2.在style.xml中定义两组主题,也就是日间主题和夜间主题
* 3.创建attrs.xml文件
* 使用代码
* 4.需要夜间模式的布局引用attr自定义属性
* 5.java代码
* a.判断储存类型
* b.点击事件,根据类型进行日夜间的切换
colors里夜间模式的设置
&color name="nightColorPrimary"&#3b3b3b&/color&
&color name="nightColorPrimaryDark"&#383838&/color&
&color name="nightColorAccent"&#a72b55&/color&
styles日间模式要添加:
&item name="android:textColor"&@android:color/black&/item&
&item name="mainBackground"&@android:color/white&/item&
夜间模式要写:
&style name="NightAppTheme" parent="Theme.AppCompat.Light.DarkActionBar"&
&!-- Customize your theme here. --&
&item name="colorPrimary"&@color/nightColorPrimary&/item&
&item name="colorPrimaryDark"&@color/nightColorPrimaryDark&/item&
&item name="colorAccent"&@color/nightColorAccent&/item&
&item name="android:textColor"&@android:color/white&/item&
&item name="mainBackground"&@color/nightColorPrimaryDark&/item&
在values里创建attrs.xml文件,然后定义属性&attr name="mainBackground" format="color|reference"/&
在activity_main.xml引用夜间模式:
注意这里引用一下我们自定义的attr资源Android:background="?attr/mainBackground",可以使用到此属性的控件带有日夜间模式切换
紧接着就是java类了,先设置点击事件然后就要储存状态点击事件要做一个判断用三元运算符或者if,else都行至于方法我都给陈列下来了.
在这本人犯了个小小的错误,请大家原谅那就是我调用onSaveInstanceState的时候因为疏忽调用错了
一下图片就是我错的那个方法:
下面这个方法是正确的:
本人不时也会出错,所以有错请大家多多指导
AndroidSDK Support自带夜间、日间模式切换详解
日间、夜间模式切换
日间模式转换夜间模式
夜/日间模式切换
夜间与日间模式的切换
Android主题切换—夜间/白天模式探究
没有更多推荐了,怎样切换日间怎样切换到日间模式?_百度知道
怎样切换日间怎样切换到日间模式?
怎样切换日间怎样切换到日间模式?
答题抽奖
首次认真答题后
即可获得3次抽奖机会,100%中奖。
开启日间模式
为您推荐:
其他类似问题
换一换
回答问题,赢新手礼包
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。手机怎样调回日间模式_百度知道
手机怎样调回日间模式
手机怎样调回日间模式
答题抽奖
首次认真答题后
即可获得3次抽奖机会,100%中奖。
部分三星手机自带浏览器支持夜间模式,操作方式:互联网-打开某个网页-右上角更多-启用夜间模式。如需关闭夜间模式:互联网-打开网页-更多-禁用夜间模式。
三星产品问答服务
主营:电子产品
为您推荐:
其他类似问题
您可能关注的内容
换一换
回答问题,赢新手礼包
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。由于项目需求,需要进行日间和夜间模式的切换,经过实践和网上的资料,大概的实现方式如下:
1.通常来说日间和夜间模式的切换会出现在设置里面。在项目中,我使用NSUserDefault来存储一个Key为Mode的值,日间模式值则为Day,夜间为Night,设置中根据切换的模式来进行键值的更新。更新之后,使用NSNotificationCenter发出通知。
2.需要切换模式的ViewController中,可以定义一个isDay的BOOL值。并且需要作为通知的接收器来接收设置中按钮动作触发的通知。在处理通知的方法中,根据NSUserDefault中Key为Mode的值来进行isDay的赋值。YES为白天模式,NO为夜间模式。如果是TableView的话可以进行reloadData的操作进行更新,其他View如果需要更新的话使用setNeedsDisplay。
3.在AppDelegate中需要首先判断NSUserDefault中Mode得值,如果没有的话,需要先设定一个默认值
4.需要注意的是,这种方法对于UIImageView是不起作用的。所以,我另外添加了一层View,代码如下:
1 UIView *nightModeView = [[UIView alloc] initWithFrame:self.view.frame];
3 nightModeView.background = [UIColor blackColor];
5 nightModelView.alpha = 0.5;
7 nightModeView.userInteracationEnabled = NO;
9 [self.view addSubview:nightModeView];
在夜间模式时添加。在日间模式时removeFromSuperview即可。
5.其他ViewController在加载的时候。先进行isDay的赋值。
1 self.button.background = isDay ? [UIColor whiteColor] : [UIColor blackColor];
这样就避免了改变模式后重新打开app还是默认的颜色
思路总结下来就是使用KVO来进行模式的监听,在各个ViewController中自定义一个值来判断当前的模式。模式切换时,对各个view进行刷新。对于图片的处理,则可以使用第4点
阅读(...) 评论()

我要回帖

更多关于 计算器怎么调成音乐模式 的文章

 

随机推荐