Android 深入(二)- 利用ToolBar实现动态主题

时间:2022-06-09
本文章向大家介绍Android 深入(二)- 利用ToolBar实现动态主题,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

利用ToolBar实现主题切换原理:切换主题时,将颜色值存储到Preference中,同时更新主题样式。再次打开App读取Preference对应的颜色值,设置主题样式即可。

  • 主要使用方法如下: 1)设置ToolBar的背景颜色:toolbar.setBackgroundColor()。 2)设置窗体状态栏透明:getWindow().setStatusBarColor()。 3)设置窗体导航栏底色:getWindow().setNavigationBarColor();

首先看一下效果图:

converted_file_44df3f12.gif

1. 创建一个Activity ,设置主题为"@style/Theme.AppCompat.Light.NoActionBar"。
<activity android:name=".MainActivity"
            android:theme="@style/Theme.AppCompat.Light.NoActionBar">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
2. 在style.xml中自定义主题样式。
<resources xmlns:tools="http://schemas.android.com/tools">

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/accent_amber</item>
        <item name="colorPrimaryDark">@color/accent_amber</item>
        <item name="colorAccent">@color/accent_amber</item>
    </style>

    <style name="MyToolbar" parent="Widget.AppCompat.Toolbar">
        <item name="android:layout_width">match_parent</item>
        <item name="android:layout_height">wrap_content</item>
        <item name="android:elevation" tools:ignore="NewApi">5dp</item>
        <item name="theme">@style/MyToolbarTheme</item>

    </style>

    <style name="MyToolbarTheme" parent="ThemeOverlay.AppCompat.ActionBar">
        <item name="android:textColorPrimary">#FFF</item>
        <item name="colorControlNormal">#FFF</item>
        <item name="colorControlHighlight">#FFF</item>
    </style>
</resources>
3. 自定义toolbar.xml,使用自定义的主题MyToolBar。
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar
    xmlns:android="http://schemas.android.com/apk/res/android"
    style="@style/MyToolbar"
    android:layout_height="wrap_content"
    android:layout_width="match_parent"
    />
4. 在Activity布局中使用toolbar.xml。
<?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/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <include
        android:id="@+id/toolbar"
        layout="@layout/toolbar" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!" />
</LinearLayout>
5. 设置主题基础ThemeActivity,负责设置更改主题。
package cn.studyou.themedeep.base;

import android.annotation.TargetApi;
import android.app.ActivityManager;
import android.content.Context;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.SwitchCompat;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.RadioButton;
import android.widget.ScrollView;
import android.widget.SeekBar;

import com.mikepenz.iconics.IconicsDrawable;
import com.mikepenz.iconics.context.IconicsContextWrapper;
import com.mikepenz.iconics.typeface.IIcon;

import java.util.ArrayList;

import cn.studyou.themedeep.R;
import cn.studyou.themedeep.utils.ColorPaletteUtils;
import cn.studyou.themedeep.utils.PreferenceUtils;
import cn.studyou.themedeep.utils.ThemeUtils;

/**
 * 基本功能:主题
 * 创建:王杰
 * 创建时间:2017/2/27
 * 邮箱:w489657152@gmail.com
 */

public class ThemeActivity extends AppCompatActivity {
    private ThemeUtils themeUtils;
    private PreferenceUtils SP;
    private boolean coloredNavBar;
    private boolean obscuredStatusBar;
    private boolean applyThemeImgAct;


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        SP = PreferenceUtils.getInstance(getApplicationContext());
        themeUtils = new ThemeUtils(getApplicationContext());
    }

    @Override
    public void onResume() {
        super.onResume();
        updateTheme();
    }

    public void updateTheme() {
        themeUtils.updateTheme();
        coloredNavBar = SP.getBoolean(getString(R.string.preference_colored_nav_bar), false);
        obscuredStatusBar = SP.getBoolean(getString(R.string.preference_translucent_status_bar), true);
        applyThemeImgAct = SP.getBoolean(getString(R.string.preference_apply_theme_pager), true);
    }

    @Override
    protected void attachBaseContext(Context newBase) {
        // NOTE: icons stuff
        super.attachBaseContext(IconicsContextWrapper.wrap(newBase));
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public void setNavBarColor() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            if (isNavigationBarColored()) getWindow().setNavigationBarColor(getPrimaryColor());
            else
                getWindow().setNavigationBarColor(ContextCompat.getColor(getApplicationContext(), R.color.md_black_1000));
        }
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    protected void setStatusBarColor() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            if (isTranslucentStatusBar())
                getWindow().setStatusBarColor(ColorPaletteUtils.getObscuredColor(getPrimaryColor()));
            else
                getWindow().setStatusBarColor(getPrimaryColor());
        }
    }

    protected void setScrollViewColor(ScrollView scr) {
        themeUtils.setScrollViewColor(scr);
    }

    public void setCursorDrawableColor(EditText editText, int color) {
        // TODO: 02/08/16 remove this
        ThemeUtils.setCursorDrawableColor(editText, color);
    }


    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public void setRecentApp(String text) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            BitmapDrawable drawable = ((BitmapDrawable) getDrawable(R.mipmap.ic_launcher));
            setTaskDescription(new ActivityManager.TaskDescription(text, drawable.getBitmap(), getPrimaryColor()));
        }
    }


    public boolean isNavigationBarColored() {
        return coloredNavBar;
    }

    public boolean isTranslucentStatusBar() {
        return obscuredStatusBar;
    }

    protected boolean isApplyThemeOnImgAct() {
        return applyThemeImgAct;
    }

    protected boolean isTransparencyZero() {
        return 255 - SP.getInt(getString(R.string.preference_transparency), 0) == 255;
    }

    public int getTransparency() {
        return 255 - SP.getInt(getString(R.string.preference_transparency), 0);
    }

    public void setBaseTheme(int baseTheme, boolean permanent) {
        themeUtils.setBaseTheme(baseTheme, permanent);
    }

    public void themeSeekBar(SeekBar bar) {
        themeUtils.themeSeekBar(bar);
    }

    public int getPrimaryColor() {
        return themeUtils.getPrimaryColor();
    }

    public int getAccentColor() {
        return themeUtils.getAccentColor();
    }

    public int getBaseTheme() {
        return themeUtils.getBaseTheme();
    }

    protected int getBackgroundColor() {
        return themeUtils.getBackgroundColor();
    }

    protected Drawable getPlaceHolder() {
        return themeUtils.getPlaceHolder();
    }

    protected int getInvertedBackgroundColor() {
        return themeUtils.getInvertedBackgroundColor();
    }

    public int getTextColor() {
        return themeUtils.getTextColor();
    }

    public int getSubTextColor() {
        return themeUtils.getSubTextColor();
    }

    public int getCardBackgroundColor() {
        return themeUtils.getCardBackgroundColor();
    }

    public int getIconColor() {
        return themeUtils.getIconColor();
    }

    protected int getDrawerBackground() {
        return themeUtils.getDrawerBackground();
    }

    public int getDialogStyle() {
        return themeUtils.getDialogStyle();
    }

    protected int getPopupToolbarStyle() {
        return themeUtils.getPopupToolbarStyle();
    }

    protected ArrayAdapter<String> getSpinnerAdapter(ArrayList<String> items) {
        return themeUtils.getSpinnerAdapter(items);
    }

    protected int getDefaultThemeToolbarColor3th() {
        return themeUtils.getDefaultThemeToolbarColor3th();
    }

    protected void updateRadioButtonColor(RadioButton radioButton) {
        themeUtils.updateRadioButtonColor(radioButton);
    }

    protected void setRadioTextButtonColor(RadioButton radioButton, int color) {
        themeUtils.setRadioTextButtonColor(radioButton, color);
    }

    public void updateSwitchColor(SwitchCompat sw, int color) {
        themeUtils.updateSwitchColor(sw, color);
    }

    public IconicsDrawable getToolbarIcon(IIcon icon) {
        return themeUtils.getToolbarIcon(icon);
    }


}
6. 所有Activity继承ThemeActivity设置主题。
package cn.studyou.themedeep.ui;

import android.content.DialogInterface;
import android.os.Build;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.CardView;
import android.support.v7.widget.SwitchCompat;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView;

import com.mikepenz.google_material_typeface_library.GoogleMaterial;

import cn.studyou.themedeep.R;
import cn.studyou.themedeep.base.ThemeActivity;
import cn.studyou.themedeep.utils.ColorPaletteUtils;
import cn.studyou.themedeep.utils.PreferenceUtils;
import uz.shift.colorpicker.LineColorPicker;
import uz.shift.colorpicker.OnColorChangedListener;

public class SettingActivity extends ThemeActivity {

    private SwitchCompat swNavBar;
    private LinearLayout swNavBarStatus;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_setting);
        initView();
    }

    private Toolbar toolbar;
    private PreferenceUtils SP;
    private Button changeThemeButton;
    private TextView toolbarTitle;
    private SwitchCompat setTranslucentStatusBar;
    private LinearLayout translucentStatusBarStatus;


    private void initView() {
        SP = PreferenceUtils.getInstance(getApplicationContext());
        toolbar = (Toolbar) findViewById(R.id.toolbar);
        toolbarTitle = (TextView) findViewById(R.id.toolbar_title);
        setSupportActionBar(toolbar);
        changeThemeButton = (Button) findViewById(R.id.changeTheme);
        setTranslucentStatusBar = (SwitchCompat) findViewById(R.id.set_translucent_status_bar);
        translucentStatusBarStatus = (LinearLayout) findViewById(R.id.translucent_status_bar_status);
        swNavBar = (SwitchCompat) findViewById(R.id.set_colored_navBar);
        swNavBarStatus = (LinearLayout) findViewById(R.id.set_colored_navBar_status);
        changeThemeButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                primaryColorPiker();
            }
        });

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            translucentStatusBarStatus.setVisibility(View.VISIBLE);
            swNavBarStatus.setVisibility(View.VISIBLE);
        }
        setTranslucentStatusBar.setChecked(SP.getBoolean(getString(R.string.preference_translucent_status_bar), true));
        setTranslucentStatusBar.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                SP.putBoolean(getString(R.string.preference_translucent_status_bar), isChecked);
                updateTheme();
                setStatusBarColor();
                updateSwitchColor(setTranslucentStatusBar, getAccentColor());
            }
        });

        toolbarTitle.setText(R.string.setting);
        toolbar.setNavigationIcon(getToolbarIcon(GoogleMaterial.Icon.gmd_arrow_back));
        toolbar.setNavigationOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                finish();
            }
        });


        swNavBar.setChecked(SP.getBoolean(getString(R.string.preference_colored_nav_bar), false));
        swNavBar.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                SP.putBoolean(getString(R.string.preference_colored_nav_bar), isChecked);
                updateTheme();
                updateSwitchColor(swNavBar, getAccentColor());
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                    getWindow().setNavigationBarColor(isNavigationBarColored() ? getPrimaryColor() : ContextCompat.getColor(getApplicationContext(), R.color.md_black_1000));
                }
            }
        });
    }


    private void primaryColorPiker() {
        final AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this, getDialogStyle());

        final View dialogLayout = getLayoutInflater().inflate(R.layout.color_piker_primary, null);
        final LineColorPicker colorPicker = (LineColorPicker) dialogLayout.findViewById(R.id.color_picker_primary);
        final LineColorPicker colorPicker2 = (LineColorPicker) dialogLayout.findViewById(R.id.color_picker_primary_2);
        final TextView dialogTitle = (TextView) dialogLayout.findViewById(R.id.cp_primary_title);
        CardView dialogCardView = (CardView) dialogLayout.findViewById(R.id.cp_primary_card);
        dialogCardView.setCardBackgroundColor(getCardBackgroundColor());

        colorPicker.setColors(ColorPaletteUtils.getBaseColors(getApplicationContext()));
        for (int i : colorPicker.getColors())
            for (int i2 : ColorPaletteUtils.getColors(getBaseContext(), i))
                if (i2 == getPrimaryColor()) {
                    colorPicker.setSelectedColor(i);
                    colorPicker2.setColors(ColorPaletteUtils.getColors(getBaseContext(), i));
                    colorPicker2.setSelectedColor(i2);
                    break;
                }

        dialogTitle.setBackgroundColor(getPrimaryColor());

        colorPicker.setOnColorChangedListener(new OnColorChangedListener() {
            @Override
            public void onColorChanged(int c) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                    if (isTranslucentStatusBar()) {
                        getWindow().setStatusBarColor(ColorPaletteUtils.getObscuredColor(getPrimaryColor()));
                    } else getWindow().setStatusBarColor(c);
                }

                toolbar.setBackgroundColor(c);
                dialogTitle.setBackgroundColor(c);
                colorPicker2.setColors(ColorPaletteUtils.getColors(getApplicationContext(), colorPicker.getColor()));
                colorPicker2.setSelectedColor(colorPicker.getColor());
            }
        });
        colorPicker2.setOnColorChangedListener(new OnColorChangedListener() {
            @Override
            public void onColorChanged(int c) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                    if (isTranslucentStatusBar()) {
                        getWindow().setStatusBarColor(ColorPaletteUtils.getObscuredColor(c));
                    } else getWindow().setStatusBarColor(c);
                    if (isNavigationBarColored())
                        getWindow().setNavigationBarColor(c);
                    else
                        getWindow().setNavigationBarColor(ContextCompat.getColor(getApplicationContext(), R.color.md_black_1000));
                }
                toolbar.setBackgroundColor(c);
                dialogTitle.setBackgroundColor(c);
            }
        });
        dialogBuilder.setView(dialogLayout);

        dialogBuilder.setNeutralButton(getString(R.string.cancel).toUpperCase(), new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                    if (isTranslucentStatusBar()) {
                        getWindow().setStatusBarColor(ColorPaletteUtils.getObscuredColor(getPrimaryColor()));
                    } else getWindow().setStatusBarColor(getPrimaryColor());
                }
                toolbar.setBackgroundColor(getPrimaryColor());
                dialog.cancel();
            }
        });

        dialogBuilder.setPositiveButton(getString(R.string.ok_action).toUpperCase(), new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int which) {
                SP.putInt(getString(R.string.preference_primary_color), colorPicker2.getColor());
                updateTheme();
                setNavBarColor();
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                    if (isTranslucentStatusBar()) {
                        getWindow().setStatusBarColor(ColorPaletteUtils.getObscuredColor(getPrimaryColor()));
                    } else {
                        getWindow().setStatusBarColor(getPrimaryColor());
                    }
                }
            }
        });

        dialogBuilder.setOnDismissListener(new DialogInterface.OnDismissListener() {
            @Override
            public void onDismiss(DialogInterface dialog) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                    if (isTranslucentStatusBar()) {
                        getWindow().setStatusBarColor(ColorPaletteUtils.getObscuredColor(getPrimaryColor()));
                    } else getWindow().setStatusBarColor(getPrimaryColor());
                    if (isNavigationBarColored())
                        getWindow().setNavigationBarColor(getPrimaryColor());
                    else
                        getWindow().setNavigationBarColor(ContextCompat.getColor(getApplicationContext(), R.color.md_black_1000));
                }
                toolbar.setBackgroundColor(getPrimaryColor());

            }
        });
        dialogBuilder.show();
    }

    @Override
    public void onResume() {
        super.onResume();
        updateNowTheme();
    }

    private void updateNowTheme() {
        toolbar.setPopupTheme(getPopupToolbarStyle());
        toolbar.setBackgroundColor(getPrimaryColor());
        toolbar.setTitle("");

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            if (isTranslucentStatusBar()) {
                getWindow().setStatusBarColor(ColorPaletteUtils.getObscuredColor(getPrimaryColor()));
            } else {
                getWindow().setStatusBarColor(getPrimaryColor());
            }
            getWindow().setNavigationBarColor(isNavigationBarColored() ? getPrimaryColor() : ContextCompat.getColor(getApplicationContext(), R.color.md_black_1000));
        }
    }
}
7. 选取主题颜色写到color.xml中供后续使用(更多颜色值见源码)。
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!--Accent Color Collection-->
    <color name="accent_red">#f44336</color>
    <color name="accent_pink">#e91e63</color>
    <color name="accent_purple">#9c27b0</color>
    <color name="accent_deep_purple">#673ab7</color>
    <color name="accent_indago">#3f51b5</color>
    <color name="accent_blue">#2196f3</color>
    <color name="accent_cyan">#00bcd4</color>
    <color name="accent_teal">#009688</color>
    <color name="accent_green">#4caf50</color>
    <color name="accent_yellow">#ffeb3b</color>
    <color name="accent_amber">#ffc107</color>
    <color name="accent_orange">#ff9800</color>
    <color name="accent_brown">#795548</color>
    <color name="accent_white">#FFFFFF</color>
    <color name="accent_grey">#9e9e9e</color>
    <color name="accent_black">#000000</color>
</resources>

总结:

  • 阅读了LeafPic的源码,觉得主题切换真的很不错,就提炼出来,其实原理很简单,供做主题切换的同学借鉴。
  • 同时希望大家多阅读优秀的代码,提升自己。
  • 本文源码地址:ThemeDeep