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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25815769/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 09:44:34  来源:igfitidea点击:

How to _really_ programmatically change primary and accent color in Android Lollipop?

androidandroid-5.0-lollipop

提问by nhaarman

First of all, this questionasks a very similar question. However, my question has a subtle difference.

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

What I'd like to know is whether it is possible to programmatically change the colorPrimaryattribute of a theme to an arbitrarycolor?

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

So for example, we have:

例如,我们有:

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

At runtime, the user decides he wants to use #ccffffas a primary color. Ofcourse there's no way I can create themes for all possible colors.

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

I don't mind if I have to do hacky stuff, like relying on Android's private internals, as long as it works using the public SDK.

我不介意我是否必须做一些骇人听闻的事情,例如依赖 Android 的私有内部结构,只要它使用公共 SDK 即可。

My goal is to eventually have the ActionBarandall widgets like a CheckBoxto use this primary color.

我的目标是最终拥有ActionBar所有小工具喜欢CheckBox使用这种原色。

回答by Chris Banes

Themes are immutable, you can't.

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

回答by JavierSegoviaCordoba

I read the comments about contacts app and how it use a theme for each contact.

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

Probably, contacts app has some predefine themes (for each material primary color from here: http://www.google.com/design/spec/style/color.html).

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

You can apply a theme before a the setContentView method inside onCreate method.

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

Then the contacts app can apply a theme randomly to each user.

然后,联系人应用程序可以为每个用户随机应用一个主题。

This method is:

这种方法是:

setTheme(R.style.MyRandomTheme);

But this method has a problem, for example it can change the toolbar color, the scroll effect color, the ripple color, etc, but it cant change the status bar color and the navigation bar color (if you want to change it too).

但是这个方法有一个问题,比如它可以改变工具栏颜色、滚动效果颜色、波纹颜色等,但不能改变状态栏颜色和导航栏颜色(如果你也想改变的话)。

Then for solve this problem, you can use the method before and:

那么为了解决这个问题,你可以使用之前的方法和:

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

This two method change the navigation and status bar color. Remember, if you set your navigation bar translucent, you can't change its color.

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

This should be the final code:

这应该是最终的代码:

@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);

}

You can use a switch and generate random number to use random themes, or, like in contacts app, each contact probably has a predefine number associated.

您可以使用开关并生成随机数以使用随机主题,或者,就像在联系人应用程序中一样,每个联系人可能都有一个关联的预定义号码。

A sample of theme:

主题示例:

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

Sorry for my english.

对不起我的英语不好。

回答by devconsole

You can use Theme.applyStyleto modify your theme at runtime by applying another style to it.

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

Let's say you have these style definitions:

假设您有这些样式定义:

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

Now you can patch your theme at runtime like so:

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

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

The method applyStylehas to be called before the layout gets inflated! So unless you load the view manually you should apply styles to the theme before calling setContentViewin your activity.

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

Of course this cannot be used to specify an arbitrary color, i.e. one out of 16 million (2563) colors. But if you write a small program that generates the style definitions and the Java code for you then something like one out of 512 (83) should be possible.

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

What makes this interesting is that you can use different style overlays for different aspects of your theme. Just add a few overlay definitions for colorAccentfor example. Now you can combine different values for primary color and accent color almostarbitrarily.

有趣的是,您可以为主题的不同方面使用不同的样式叠加。例如,只需添加一些叠加定义colorAccent。现在,您几乎可以任意组合原色和强调色的不同值。

You should make sure that your overlay theme definitions don't accidentally inherit a bunch of style definitions from a parent style definition. For example a style called AppTheme.OverlayRedimplicitly inherits all styles defined in AppThemeand all these definitions will also be applied when you patch the master theme. So either avoid dots in the overlay theme names or use something like Overlay.Redand define Overlayas an empty style.

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

回答by IQ.feature

I've created some solution to make any-color themes, maybe this can be useful for somebody. API 9+

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

1.first create "res/values-v9/" and put there this file: styles.xmland regular "res/values" folder will be used with your styles.

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

2.put this code in your res/values/styles.xml:

2.将此代码放在您的 res/values/styles.xml 中:

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

3.in to AndroidManifest:

3.进入AndroidManifest:

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

4.create a new class with name "ThemeColors.java"

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

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

5.MainActivity:

5. 主要活动

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        new ThemeColors(this);
        setContentView(R.layout.activity_main);
    }

    public void buttonClick(View view){
        int red= new Random().nextInt(255);
        int green= new Random().nextInt(255);
        int blue= new Random().nextInt(255);
        ThemeColors.setNewThemeColor(MainActivity.this, red, green, blue);
    }
}

To change color, just replace Random with your RGB, Hope this helps.

要更改颜色,只需将 Random 替换为您的 RGB,希望这会有所帮助。

enter image description here

在此处输入图片说明

There is a complete example: ColorTest.zip

有一个完整的例子:ColorTest.zip

回答by lgallard

I used the Dahnark's code but I also need to change the ToolBar background:

我使用了 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));
}

回答by varghesekutty

You cannot change the color of colorPrimary, but you can change the theme of your application by adding a new style with a different colorPrimary color

您无法更改 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>

and inside the activity set theme

并在活动设置主题内

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

回答by yeahdixon

from an activity you can do:

从你可以做的活动中:

getWindow().setStatusBarColor(i color);

回答by Michael Kern

USE A TOOLBAR

使用工具栏

You can set a custom toolbaritem color dynamically by creating a custom toolbar class:

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

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



}

then refer to it in your layout file. Now you can set a custom color using

然后在您的布局文件中引用它。现在您可以使用设置自定义颜色

toolbar.setItemColor(Color.Red);

Sources:

资料来源:

I found the information to do this here: How to dynamicaly change Android Toolbar icons color

我在这里找到了执行此操作的信息:如何动态更改 Android 工具栏图标颜色

and then I edited it, improved upon it, and posted it here: GitHub:AndroidDynamicToolbarItemColor

然后我编辑它,改进它,并把它贴在这里:GitHub:AndroidDynamicToolbarItemColor

回答by Ustaad

This is what you CAN do:

这是你可以做的:

write a file in drawable folder, lets name it background.xml

在 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>

then set your Layout's (or what so ever the case is) android:background="@drawable/background"

然后设置您的布局(或任何情况) android:background="@drawable/background"

on setting your theme this color would represent the same.

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