DayNightModeChange_Android日间模式和夜间模式切换

先上酷炫的运行效果

day_night_themechange.gif

日夜间模式在app上面的使用场景还是很多的,特别是有关阅读类的app,不同的光线条件下让用户选择不同的主题模式那是必须得。其实实现这样的需求也很简单,下面就来看看我的方法吧。

实现前的分析

不同的模式下 View或activity需要设置不同的resource(这里resource可以是color、mipmap、style等资源),那么怎么让resource不同呢? 只需要让resource根据不同的模式设置不同的名称,然后根据不同的名称获取到不同的resourceId就可以了

具体示例

HomeActivity的代码如下:

package com.example.idea.daynightmodechange;

import android.app.Activity;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.example.idea.daynightmodechange.config.Config;
import com.example.idea.daynightmodechange.theme.IThemeable;
import com.example.idea.daynightmodechange.theme.ThemeManager;
import com.example.idea.daynightmodechange.theme.ThemeUtils;

import butterknife.BindView;
import butterknife.ButterKnife;

public class HomeActivity extends Activity implements IThemeable {


    @BindView(R.id.ll_container)
    LinearLayout ll_container;
    @BindView(R.id.tv_text1)
    TextView tv_text1;
    @BindView(R.id.tv_text2)
    TextView tv_text2;
    @BindView(R.id.iv_image)
    ImageView iv_image;
    @BindView(R.id.btn_change_mode)
    Button btn_change_mode;
    @BindView(R.id.btn_jump)
    Button btn_jump;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getThemeManager().applyTheme(HomeActivity.this, R.style.AppTheme);

        setContentView(R.layout.act_home);
        ButterKnife.bind(this);

        initView();

    }

    private void initView() {
        btn_change_mode.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (Config.currentTheme == ThemeManager.THEME.DAY) {
                    getThemeManager().changeTheme(ThemeManager.THEME.NIGHT);
                } else {
                    getThemeManager().changeTheme(ThemeManager.THEME.DAY);
                }

                applyTheme();


            }
        });

        btn_jump.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                startActivity(new Intent(HomeActivity.this,TestStyleActivity.class));
            }
        });
    }

    @Override
    public void applyTheme() {
        getThemeManager().applyBackgroundColor(ll_container, R.color.color_home_bg);
        getThemeManager().applyTextColor(tv_text1, R.color.color_text);
        getThemeManager().applyImageResource(iv_image, R.drawable.shape_iv_bg);
        getThemeManager().applyBackgroundDrawable(btn_jump, R.drawable.selector_text_bg);
        getThemeManager().applyBackgroundDrawable(btn_change_mode, R.drawable.selector_text_bg);
    }

    @Override
    public ThemeManager getThemeManager() {
        return ThemeManager.getInstance();
    }

    @Override
    public boolean isThemeEnable() {
        return true;
    }
}

对应的布局文件:





    

    

    

    

用一个枚举类型来表示你需要切换的模式,这里我只使用了日间模式和夜间模式这两个。

    public static enum THEME {
        DAY, NIGHT("_night"); //你������可以添加多种模式在这里,不同的模式应该具有不同的后缀

        String resPrefix;

        private THEME() {
            resPrefix = "";
        }

        private THEME(String prefix) {
            resPrefix = prefix;
        }

        /**
         * 资源名称
         * @param name
         * @return
         */
        public String formatResName(String name) {
            return name + resPrefix;
        }

        public boolean hasResPrefix() {
            return !TextUtils.isEmpty(resPrefix);
        }
    }

这里通过切换模式后ll_container的背景颜色的改变来分析
a.我在colors资源里,为ll_container准备了两份颜色值,这里一定要在
"color_home_bg"后面加上"_night",与枚举相对应,为了后面通过资源Id和枚举类型获取对应的资源Id。

#e5e5e5
#80444444

b.当我要切换模式的时候,针对ll_container这个view调用

getThemeManager().applyBackgroundColor(ll_container, R.color.color_home_bg);

c.我们来看一下它具体的方法实现

public ThemeManager applyBackgroundColor(Context context, View view,
                                            int backgroundResourceId) {
        view.setBackgroundResource(ThemeUtils.processColorResId(context,
                this.theme, backgroundResourceId));
        return this;
    }


    /**
     * 
     * @param view 要设置的view
     * @param backgroundResourceId 资源id
     * @return
     */
    public ThemeManager applyBackgroundColor(View view, int backgroundResourceId) {
        return applyBackgroundColor(view.getContext(), view,
                backgroundResourceId);
    }

d.ThemeUtils.processColorResId(context,this.theme, backgroundResourceId)这个方法的作用是根据当前资源id和theme获取到对应的资源id

public static int processColorResId(Context context,
                                    ThemeManager.THEME theme, int resourceId) {
    return processThemeResId(context, theme, "color", resourceId);
}

/**
     * 
     * @param context
     * @param theme 当前主题
     * @param defType 对应的资源类别
     * @param resourceId 
     * @return
     */
    private static int processThemeResId(Context context,
                                         ThemeManager.THEME theme, String defType, int resourceId) {
        if (theme.hasResPrefix() && isThemeEnable(context)) {
            String strThemeResName = processThemeResName(theme, context
                    .getResources().getResourceName(resourceId));
            return context.getResources().getIdentifier(strThemeResName,
                    defType, context.getPackageName());
        } else {
            return resourceId;
        }
    }

这样就完成了ll_contianer的背景色切换,是不是很easy.
切换别的view的资源与这个类似,这里就不一一列举了。

需要注意的地方

当我们app中使用沉浸式状态栏实现时候,一定希望状态栏和标题栏能在进行模式切换的时候改变样式,但是状态栏和标题栏的样式的切换只能在Activity的setContentView()方法之前执行,上面的方法就不能用来切换状态栏和标题栏的样式了。

想要切换状态栏和标题栏的样式,可以用recreate()方法来重启Activity来实现,Activity重启会有闪烁的问题可以通过动画来过渡。

后续

官方在Android Support Library 23.2开始支持了夜间模式切换,有关23.2的夜间模式切换,请戳这里【还没写】。


源码地址 https://github.com/idea007/DayNightModeChange

你可能感兴趣的:(DayNightModeChange_Android日间模式和夜间模式切换)