如何_really_以编程方式更改Android Lollipop中的主色和强调色?

时间:2014-09-12 19:48:31

标签: android android-5.0-lollipop

首先,this question提出了一个非常相似的问题。但是,我的问题有一个微妙的区别。

我想知道的是,是否可以通过编程方式将主题的colorPrimary属性更改为 任意 颜色?

例如,我们有:

<style name="AppTheme" parent="android:Theme.Material.Light">
    <item name="android:colorPrimary">#ff0000</item>
    <item name="android:colorAccent">#ff0000</item>
</style>

在运行时,用户决定使用#ccffff作为主要颜色。当然,我无法为所有可能的颜色创建主题。

我不介意我是否必须做hacky的东西,比如依赖Android的私人内部,只要它使用公共SDK。

我的目标是最终让ActionBar 所有小部件(例如CheckBox)都使用此主要颜色。

9 个答案:

答案 0 :(得分:164)

主题是不可改变的,你不能。

答案 1 :(得分:61)

我阅读了有关联系人应用的评论以及它如何为每个联系人使用主题。

联系人应用程序可能有一些预定义的主题(对于每种材质原色:http://www.google.com/design/spec/style/color.html)。

您可以在onCreate方法中的setContentView方法之前应用主题。

然后,联系人应用可以随机向每个用户应用主题。

此方法是:

setTheme(R.style.MyRandomTheme);

但这种方法存在问题,例如它可以更改工具栏颜色,滚动效果颜色,纹波颜色等,但它无法更改状态栏颜色和导航栏颜色(如果要更改它)太)。

然后,为了解决这个问题,您可以使用之前的方法:

if (Build.VERSION.SDK_INT >= 21) {
        getWindow().setNavigationBarColor(getResources().getColor(R.color.md_red_500));
        getWindow().setStatusBarColor(getResources().getColor(R.color.md_red_700));
    }

这两种方法可以更改导航和状态栏颜色。 请记住,如果您将导航栏设置为半透明,则无法更改其颜色。

这应该是最终的代码:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setTheme(R.style.MyRandomTheme);
    if (Build.VERSION.SDK_INT >= 21) {
        getWindow().setNavigationBarColor(getResources().getColor(R.color.myrandomcolor1));
        getWindow().setStatusBarColor(getResources().getColor(R.color.myrandomcolor2));
    }
    setContentView(R.layout.activity_main);

}

您可以使用开关并生成随机数以使用随机主题,或者,如在联系人应用中,每个联系人可能都有一个预定义的数字关联。

主题样本:

<style name="MyRandomTheme" parent="Theme.AppCompat.NoActionBar">
    <!-- Customize your theme here. -->
    <item name="colorPrimary">@color/myrandomcolor1</item>
    <item name="colorPrimaryDark">@color/myrandomcolor2</item>
    <item name="android:navigationBarColor">@color/myrandomcolor1</item>
</style>

抱歉我的英文。

答案 2 :(得分:42)

您可以使用Theme.applyStyle在运行时通过应用其他样式来修改主题。

假设您有这些样式定义:

<style name="DefaultTheme" parent="Theme.AppCompat.Light">
    <item name="colorPrimary">@color/md_lime_500</item>
    <item name="colorPrimaryDark">@color/md_lime_700</item>
    <item name="colorAccent">@color/md_amber_A400</item>
</style>

<style name="OverlayPrimaryColorRed">
    <item name="colorPrimary">@color/md_red_500</item>
    <item name="colorPrimaryDark">@color/md_red_700</item>
</style>

<style name="OverlayPrimaryColorGreen">
    <item name="colorPrimary">@color/md_green_500</item>
    <item name="colorPrimaryDark">@color/md_green_700</item>
</style>

<style name="OverlayPrimaryColorBlue">
    <item name="colorPrimary">@color/md_blue_500</item>
    <item name="colorPrimaryDark">@color/md_blue_700</item>
</style>

现在您可以在运行时修补主题,如下所示:

getTheme().applyStyle(R.style.OverlayPrimaryColorGreen, true);

必须在布局膨胀之前调用方法applyStyle!因此,除非您手动加载视图,否则应在调用活动中的setContentView之前将样式应用于主题。

当然,这不能用于指定任意颜色,即1600万(256 3 )颜色中的一种颜色。但是如果你编写一个为你生成样式定义和Java代码的小程序,那么就应该可以使用512(8 3 )中的一个。

令人感兴趣的是,您可以针对主题的不同方面使用不同的样式叠加层。只需为colorAccent添加一些叠加定义即可。现在,你可以任意组合原色和强调色几乎的不同值。

您应该确保您的叠加主题定义不会意外地从父样式定义继承一堆样式定义。例如,名为AppTheme.OverlayRed的样式隐式继承AppTheme中定义的所有样式,并且在修补主题时也将应用所有这些定义。因此,要么避免覆盖主题名称中的点,要么使用Overlay.Red之类的内容,并将Overlay定义为空样式。

答案 3 :(得分:17)

我已经创建了一些解决方案来制作任何颜色的主题,这可能对某些人有用。 API 9 +

1。首先创建“ res / values-v9 / ”并将此文件放在那里:styles.xml 常规的“res / values”文件夹将与你的风格一起使用。

2。将此代码放入res / values / styles.xml:

private void Update()
{
    if (Input.GetMouseButtonDown(0) && canClick)
    {
        Vector3 mouseWorldPosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
        mouseWorldPosition.z = player.transform.position.z;
        directionVector = player.transform.position - mouseWorldPosition;
        player.GetComponent<Rigidbody2D>().AddForce(directionVector.normalized * speed);
        Quaternion InstanceRotation = Quaternion.Euler(mouseWorldPosition.x - 90f, 0f, 0f);
        GameObject effect = Instantiate(SteamFx, mouseWorldPosition, InstanceRotation);
        effect.transform.LookAt(directionVector);
    }
}

3。进入AndroidManifest:

<resources>
    <style name="AppTheme" parent="Theme.AppCompat.Light">
        <item name="colorPrimary">#000</item>
        <item name="colorPrimaryDark">#000</item>
        <item name="colorAccent">#000</item>
        <item name="android:windowAnimationStyle">@style/WindowAnimationTransition</item>
    </style>

    <style name="AppThemeDarkActionBar" parent="Theme.AppCompat.Light.DarkActionBar">
        <item name="colorPrimary">#000</item>
        <item name="colorPrimaryDark">#000</item>
        <item name="colorAccent">#000</item>
        <item name="android:windowAnimationStyle">@style/WindowAnimationTransition</item>
    </style>

    <style name="WindowAnimationTransition">
        <item name="android:windowEnterAnimation">@android:anim/fade_in</item>
        <item name="android:windowExitAnimation">@android:anim/fade_out</item>
    </style>
</resources>

4. 创建一个名为“ThemeColors.java”的新类

<application android:theme="@style/AppThemeDarkActionBar">

5。,在调用 setContentView(R.layout.activity_main)之前,只需添加:

public class ThemeColors {

    private static final String NAME = "ThemeColors", KEY = "color";

    @ColorInt
    public int color;

    public ThemeColors(Context context) {
        SharedPreferences sharedPreferences = context.getSharedPreferences(NAME, Context.MODE_PRIVATE);
        String stringColor = sharedPreferences.getString(KEY, "004bff");
        color = Color.parseColor("#" + stringColor);

        if (isLightActionBar()) context.setTheme(R.style.AppTheme);
        context.setTheme(context.getResources().getIdentifier("T_" + stringColor, "style", context.getPackageName()));
    }

    public static void setNewThemeColor(Activity activity, int red, int green, int blue) {
        int colorStep = 15;
        red = Math.round(red / colorStep) * colorStep;
        green = Math.round(green / colorStep) * colorStep;
        blue = Math.round(blue / colorStep) * colorStep;

        String stringColor = Integer.toHexString(Color.rgb(red, green, blue)).substring(2);
        SharedPreferences.Editor editor = activity.getSharedPreferences(NAME, Context.MODE_PRIVATE).edit();
        editor.putString(KEY, stringColor);
        editor.apply();

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) activity.recreate();
        else {
            Intent i = activity.getPackageManager().getLaunchIntentForPackage(activity.getPackageName());
            i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
            activity.startActivity(i);
        }
    }

    private boolean isLightActionBar() {// Checking if title text color will be black
        int rgb = (Color.red(color) + Color.green(color) + Color.blue(color)) / 3;
        return rgb > 210;
    }
}

更改颜色用RGB代替Random:

new ThemeColors(this);

enter image description here

答案 4 :(得分:3)

我使用了Dahnark的代码,但我还需要更改ToolBar背景:

if (dark_ui) {
    this.setTheme(R.style.Theme_Dark);

    if (Build.VERSION.SDK_INT >= 21) {
        getWindow().setNavigationBarColor(getResources().getColor(R.color.Theme_Dark_primary));
        getWindow().setStatusBarColor(getResources().getColor(R.color.Theme_Dark_primary_dark));
    }
} else {
    this.setTheme(R.style.Theme_Light);
}

setContentView(R.layout.activity_main);

toolbar = (Toolbar) findViewById(R.id.app_bar);

if(dark_ui) {
    toolbar.setBackgroundColor(getResources().getColor(R.color.Theme_Dark_primary));
}

答案 5 :(得分:-1)

您不能更改colorPrimary的颜色,但是可以通过添加具有不同colorPrimary颜色的新样式来更改应用程序的主题

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

<style name="AppTheme.NewTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="colorPrimary">@color/colorOne</item>
    <item name="colorPrimaryDark">@color/colorOneDark</item>
</style>

并在活动设置主题内

 setTheme(R.style.AppTheme_NewTheme);
 setContentView(R.layout.activity_main);

答案 6 :(得分:-4)

来自您可以执行的活动:

getWindow().setStatusBarColor(i color);

答案 7 :(得分:-4)

使用工具栏

您可以通过创建自定义工具栏类动态设置自定义工具栏项目颜色:

package view;

import android.app.Activity;
import android.content.Context;
import android.graphics.ColorFilter;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.support.v7.internal.view.menu.ActionMenuItemView;
import android.support.v7.widget.ActionMenuView;
import android.support.v7.widget.Toolbar;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AutoCompleteTextView;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;

public class CustomToolbar extends Toolbar{

    public CustomToolbar(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        // TODO Auto-generated constructor stub
    }

    public CustomToolbar(Context context, AttributeSet attrs) {
        super(context, attrs);
        // TODO Auto-generated constructor stub
    }

    public CustomToolbar(Context context) {
        super(context);
        // TODO Auto-generated constructor stub
        ctxt = context;
    }

    int itemColor;
    Context ctxt;

    @Override 
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        Log.d("LL", "onLayout");
        super.onLayout(changed, l, t, r, b);
        colorizeToolbar(this, itemColor, (Activity) ctxt);
    } 

    public void setItemColor(int color){
        itemColor = color;
        colorizeToolbar(this, itemColor, (Activity) ctxt);
    }



    /**
     * Use this method to colorize toolbar icons to the desired target color
     * @param toolbarView toolbar view being colored
     * @param toolbarIconsColor the target color of toolbar icons
     * @param activity reference to activity needed to register observers
     */
    public static void colorizeToolbar(Toolbar toolbarView, int toolbarIconsColor, Activity activity) {
        final PorterDuffColorFilter colorFilter
                = new PorterDuffColorFilter(toolbarIconsColor, PorterDuff.Mode.SRC_IN);

        for(int i = 0; i < toolbarView.getChildCount(); i++) {
            final View v = toolbarView.getChildAt(i);

            doColorizing(v, colorFilter, toolbarIconsColor);
        }

      //Step 3: Changing the color of title and subtitle.
        toolbarView.setTitleTextColor(toolbarIconsColor);
        toolbarView.setSubtitleTextColor(toolbarIconsColor);
    }

    public static void doColorizing(View v, final ColorFilter colorFilter, int toolbarIconsColor){
        if(v instanceof ImageButton) {
            ((ImageButton)v).getDrawable().setAlpha(255);
            ((ImageButton)v).getDrawable().setColorFilter(colorFilter);
        }

        if(v instanceof ImageView) {
            ((ImageView)v).getDrawable().setAlpha(255);
            ((ImageView)v).getDrawable().setColorFilter(colorFilter);
        }

        if(v instanceof AutoCompleteTextView) {
            ((AutoCompleteTextView)v).setTextColor(toolbarIconsColor);
        }

        if(v instanceof TextView) {
            ((TextView)v).setTextColor(toolbarIconsColor);
        }

        if(v instanceof EditText) {
            ((EditText)v).setTextColor(toolbarIconsColor);
        }

        if (v instanceof ViewGroup){
            for (int lli =0; lli< ((ViewGroup)v).getChildCount(); lli ++){
                doColorizing(((ViewGroup)v).getChildAt(lli), colorFilter, toolbarIconsColor);
            }
        }

        if(v instanceof ActionMenuView) {
            for(int j = 0; j < ((ActionMenuView)v).getChildCount(); j++) {

                //Step 2: Changing the color of any ActionMenuViews - icons that
                //are not back button, nor text, nor overflow menu icon.
                final View innerView = ((ActionMenuView)v).getChildAt(j);

                if(innerView instanceof ActionMenuItemView) {
                    int drawablesCount = ((ActionMenuItemView)innerView).getCompoundDrawables().length;
                    for(int k = 0; k < drawablesCount; k++) {
                        if(((ActionMenuItemView)innerView).getCompoundDrawables()[k] != null) {
                            final int finalK = k;

                            //Important to set the color filter in seperate thread, 
                            //by adding it to the message queue
                            //Won't work otherwise. 
                            //Works fine for my case but needs more testing

                            ((ActionMenuItemView) innerView).getCompoundDrawables()[finalK].setColorFilter(colorFilter);

//                              innerView.post(new Runnable() {
//                                  @Override
//                                  public void run() {
//                                      ((ActionMenuItemView) innerView).getCompoundDrawables()[finalK].setColorFilter(colorFilter);
//                                  }
//                              });
                        }
                    }
                }
            }
        }
    }



}

然后在布局文件中引用它。现在,您可以使用

设置自定义颜色
toolbar.setItemColor(Color.Red);

<强>来源:

我在此处找到了要执行此操作的信息:How to dynamicaly change Android Toolbar icons color

然后我对其进行了编辑,对其进行了改进,并在此处发布:GitHub:AndroidDynamicToolbarItemColor

答案 8 :(得分:-4)

这是你可以做的:

在drawable文件夹中写一个文件,让我们将其命名为background.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
    <solid android:color="?attr/colorPrimary"/>
</shape>

然后设置你的布局(或者情况就是这样)android:background="@drawable/background"

在设置主题时,此颜色代表相同。