Как _really_ программно изменить основной и акцентный цвет в Android Lollipop?

Прежде всего, этот вопрос задает очень похожий вопрос. Однако мой вопрос имеет тонкую разницу.

Что я хотел бы знать, можно ли программно изменить атрибут colorPrimary темы на произвольный цвет?

Так, например, мы имеем:

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

Во время выполнения пользователь решает, что хочет использовать #ccffff как основной цвет. Конечно, я не могу создавать темы для всех возможных цветов.

Я не возражаю, если мне приходится делать хакерские вещи, например, полагаться на частные внутренние лица Android, если они работают с использованием общедоступного SDK.

Моя цель состоит в том, чтобы в конечном итоге ActionBar и все виджеты, такие как CheckBox, использовали этот основной цвет.

Ответ 1

Темы неизменяемы, вы не можете.

Ответ 2

Я прочитал комментарии о приложении для контактов и о том, как использовать тему для каждого контакта.

Возможно, приложение для контактов имеет некоторые предопределенные темы (для каждого основного основного материала здесь: http://www.google.com/design/spec/style/color.html).

Вы можете применить тему до метода setContentView внутри метода onCreate.

Затем приложение-приложение может произвольно применять тему к каждому пользователю.

Этот метод:

setTheme(R.style.MyRandomTheme);

Но этот метод имеет проблему, например, он может изменять цвет панели инструментов, цвет эффекта прокрутки, цвет пульсации и т.д., но он не может изменить цвет строки состояния и цвет панели навигации (если вы хотите изменить его тоже).

Затем для решения этой проблемы вы можете использовать метод before и:

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>

Извините за мой английский.

Ответ 3

Вы можете использовать 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 в своей деятельности.

Конечно, это нельзя использовать для указания произвольного цвета, то есть одного из 16 миллионов (256 3) цветов. Но если вы пишете небольшую программу, которая генерирует определения стиля и код Java для вас, то должно быть возможно что-то вроде одного из 512 (8 3).

Интересно то, что вы можете использовать разные наложения стиля для разных аспектов вашей темы. Просто добавьте несколько описаний наложения для colorAccent например. Теперь вы можете комбинировать разные значения для основного цвета и цвета акцента почти произвольно.

Ответ 4

Я создал некоторое решение для создания цветных тем, возможно, это может быть полезно для кого-то. API 9+

1. сначала создайте " res/values-v9/ " и поместите туда этот файл: styles.xml и регулярная папка "res/values" будут использоваться с вашими стилями.

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. в AndroidManifest:

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

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. и перед вызовом setContentView (R.layout.activity_main) просто добавьте:

new ThemeColors(this);

для изменения цвета заменить Random на RGB:

    findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            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);
        }
    });

enter image description here

Ответ 5

Библиотека GreenMatter может помочь вам в достижении функциональности, которую вы ищете:

https://github.com/negusoft/GreenMatter

Ответ 6

Я использовал код Данарк, но мне также нужно изменить фон 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));
}

Ответ 7

Вы не можете изменить цвет 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);

Ответ 8

Это может быть не совсем то, что вы хотите, но этот ответ работает для меня.

Я хотел бы также увидеть этот метод, где вы устанавливаете один раз для всех своих действий. Но насколько я знаю, вы должны установить в каждом мероприятии, прежде чем показывать какие-либо мнения.

Для справки проверьте это:

http://www.anddev.org/applying_a_theme_to_your_application-t817.html

Изменить (скопировано с этого форума):

protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    // Call setTheme before creation of any(!) View.
     setTheme(android.R.style.Theme_Dark);

    // ...

    setContentView(R.layout.main);

}

Ответ 9

ИСПОЛЬЗОВАТЬ ИНСТРУМЕНТ

Динамический цвет элемента панели инструментов можно настроить динамически, создав собственный класс панели инструментов:

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

Источники:

Я нашел информацию, чтобы сделать это здесь: Как динамически изменить цвет значков панели инструментов Android

а затем я отредактировал его, улучшил его и разместил здесь: GitHub: AndroidDynamicToolbarItemColor

Ответ 10

Это то, что вы МОЖЕТЕ сделать:

напишите файл в папке с возможностью переноса, давайте назовите его 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"

при настройке вашей темы этот цвет будет представлять то же самое.

Ответ 11

из действия, которое вы можете сделать:

getWindow().setStatusBarColor(i color);