美文网首页
DayNightModeChange_Android日间模式和夜

DayNightModeChange_Android日间模式和夜

作者: dafaycoding | 来源:发表于2016-12-22 15:14 被阅读272次

    先上酷炫的运行效果

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

    对应的布局文件:

    
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/ll_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/color_home_bg"
        android:orientation="vertical"
        tools:context="com.example.idea.daynightmodechange.HomeActivity">
    
        <TextView
            android:id="@+id/tv_text1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:layout_marginTop="17dp"
            android:text="这是测试的TextView 要改变"
            android:textColor="@color/color_text"
            android:textSize="17sp" />
    
        <TextView
            android:id="@+id/tv_text2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:layout_marginTop="17dp"
            android:text="这是测试的TextView 不改变模式"
            android:textColor="@color/color_text"
            android:textSize="17sp" />
    
        <ImageView
            android:id="@+id/iv_image"
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:layout_gravity="center_horizontal"
            android:layout_marginTop="17dp"
            android:src="@drawable/shape_iv_bg" />
    
        <Button
            android:id="@+id/btn_change_mode"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:layout_marginTop="17dp"
            android:background="@drawable/selector_text_bg"
            android:padding="10dp"
            android:text="切换模式"
            android:textSize="17sp" />
    
        <Button
            android:id="@+id/btn_jump"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:layout_marginTop="17dp"
            android:background="@drawable/selector_text_bg"
            android:padding="10dp"
            android:text="跳转到下个Activity"
            android:textSize="17sp" />
    
    
    </LinearLayout>
    
    

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

        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。

    <color name="color_home_bg">#e5e5e5</color>
    <color name="color_home_bg_night">#80444444</color>
    

    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日间模式和夜

          本文链接:https://www.haomeiwen.com/subject/pwacvttx.html