Android Lollipopで原色とアクセントカラーをプログラムで_実際に_変更する方法は?


156

まず、この質問は非常によく似た質問をします。しかし、私の質問には微妙な違いがあります。

私が知りたいのcolorPrimaryは、テーマの属性を任意の色にプログラムで変更できるかどうかです。

たとえば、次のようになります。

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

実行時に、ユーザーは#ccffff原色として使用することを決定します。もちろん、すべての可能な色のテーマを作成する方法はありません。

パブリックSDKを使用して動作する限り、Androidのプライベート内部に依存するなど、ハックなことをしなくてもかまいません。

私の目標は、最終的にActionBar とのようなすべてのウィジェットでCheckBoxこの原色を使用することです。


1
存在しないAndroidリリースの「Androidのプライベート内部」が何かはわかりません。Lの "private internals"が、Lがプロダクションリリースに関してどのような形になるかと同じであると仮定しないでください。
CommonsWare、2014

いいえ、任意のデータをテーマに配置することはできません。つまり、colorPrimaryはアクションバーの背景、最近のバーの色、通知の色にのみ使用され、これらすべてを動的に変更できます。
alanv 2014

2
「ランタイムでスタイル属性を変更する方法」を尋ねるべきだと思います。私が見た答えはあなたができないということです。しかし、私はあなたを助けるかもしれない考えを持っています。カスタムContextWrapperを使用して、独自のリソースを提供します。これを見てください:github.com/negusoft/holoaccent/blob/master/HoloAccent/src/com/…全体として、このプロジェクトはそれを行う方法のアイデアを与えるかもしれません。
Mikooos 2014

1
ここではブレインファーティングを行っていますが、すべてのXMLは.dexファイルに変換され、JavaオブジェクトとしてAndroidアプリケーションに読み込まれます。それは、コードからテーマ全体を作成および設定し、まだ書かれていないファクトリーからテーマを生成できる必要があることを意味しませんか?大変な作業のようです。
G_V 2014年

1
@NiekHaarman方法を考えたことがありますか?
gbhall 2015

回答:


187

テーマは不変ですが、変更できません。


8
ありがとう、クリス!私が探していた答えではありませんが、私はそれと一緒に暮らす必要があると思います:)
nhaarman '22

5
こんにちは@Chris Banesですが、連絡先アプリは、連絡先のテーマの色に応じて、ステータスバーの色とツールバーの色をどのように変更しましたか?可能であれば、ユーザーが希望するカラーコードを格納するだけでよいので、Niek Haarmanのニーズはそれほど遠くないと思います。これについて詳しく説明していただけますか?私もこのようなものを作りたいと思っていますが、本当に混乱しています。
スワン

39
ステータスバーの色は、Window.setStatusBarColor()を使用して動的に変更できます。
Chris Banes 2014年

9
プログラムでテーマを作成することは可能ですか?
Andrew Orobator、2015

3
そして、ステータスバーの色を変更しながら動的にあなたもWindow.setNavigationBarColor(経由ナビゲーションバーの色を変更することができます) - API 21 :)
user802421

65

連絡先アプリに関するコメントと、各連絡先のテーマの使用方法を読みました。

おそらく、連絡先アプリにはいくつかの事前定義されたテーマがあります(ここからの各マテリアルの原色について: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));
    }

この2つのメソッドは、ナビゲーションとステータスバーの色を変更します。ナビゲーションバーを半透明に設定すると、色を変更できないことに注意してください。

これは最終的なコードです:

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

私の英語でごめんなさい。


1
お返事ありがとうございます。残念ながら、私の要求は任意の色を使用することでした。もちろん、すべての色のテーマを作成することはできません。
nhaarman、2015年

1
@DanielGomezRico-AFAIKでは、最初に設定した場所に関係なく、事前に設定したテーマをオーバーライドできます。回答に「onCreateメソッド内のsetContentViewメソッドの前にテーマを適用できる」とあります。
ToolmakerSteve

50

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)色のうちの1色を指定することはできません。ただし、スタイル定義とJavaコードを生成する小さなプログラムを作成する場合は、512(8 3)のようなものが可能です。

これが興味深いのは、テーマのさまざまな側面にさまざまなスタイルのオーバーレイを使用できることです。colorAccentたとえば、いくつかのオーバーレイ定義を追加するだけです。これで、原色とアクセントカラーのさまざまな値をほぼ任意に組み合わせることができます。

オーバーレイテーマ定義が誤って多数のスタイル定義を親スタイル定義から継承しないようにする必要があります。たとえば、と呼ばれるAppTheme.OverlayRedスタイルはで定義されたすべてのスタイルを暗黙的に継承しAppTheme、これらの定義はすべて、マスターテーマにパッチを適用するときにも適用されます。そのため、オーバーレイテーマ名にドットを使用しないか、何かOverlay.Redを使用Overlayして空のスタイルとして定義します。


11
あなたの活動を呼び出すapplyStyle前に電話setContentViewしてみてください、それはうまくいくはずです。
devconsole 2016

1
はい、はい、それはうまくいくかもしれません!私は活動ではなくフラグメントニボーでcoloraccentを変更する方法を探しています!悲しいことにそれがうまくいかなかったのはそのためです。
Dennis Anderson

ありがとう、これは大いに役立った!ただし、複数回行うことはできません。(1つはcolorPrimary、もう1つはcolorAccentなど)。私たちを手伝ってくれますか?ありがとう。stackoverflow.com/questions/41779821/…–
Thomas Vos

1
これは、もう一度+1するために2つ目のアカウントを使用したい種類の回答です。ありがとう。
Benoit Duffez 2018年

どうもありがとう、これが私が探していたものでした...このアプローチを使用して、現在のテーマのアクセントカラーを変更できるといいのですが。
Nasib

32

私は任意の色のテーマを作成するためにいくつかのソリューションを作成しました。おそらくこれは誰かにとって役立つかもしれません。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. MainActivity:

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

色を変更するには、ランダムをRGBに置き換えるだけです。

ここに画像の説明を入力してください

完全な例があります:ColorTest.zip


プロジェクトを共有できますか?
Erselan Khan

新しいプロジェクトを作成し、ファイル「styles.xml」をダウンロードして、上記のコードを使用します。幸運を。
IQ.feature 2018年

1
私は頭を context.setTheme(context.getResources().getIdentifier("T_" + stringColor, "style", context.getPackageName()));抱えることができません。このトピックについてフォローアップするための説明やリンクを教えてもらえますか?
Langusten Gustel

1
@ IQ.featureコードをGithubリポジトリにプッシュするほうがコード共有に適していると思います
Vadim Kotov

1
私がこれに落ちたので他の人のために明確にするために...異なる色でテーマの全リストを宣言するファイルres-v9 / styles.xmlがあり、コードは基本的にそれらのテーマの1つを適用し、アクティビティを再作成します。これは、他の回答でも達成しようとしたものです。つまり、プログラムでまたは動的にテーマを作成するのではなく、テーマを事前定義することによる回避策です。
frezq

3

Dahnarkのコードを使用しましたが、ツールバーの背景も変更する必要があります。

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

このコードを追加:android:background = "?attr / colorPrimary"、ツールバー(.xmlファイル)に、Javaで背景を設定する必要はありません。
JavierSegoviaCordoba 2015

しかし、私は2つの異なるツールバーを使用しています。1つは明るいテーマ用、もう1つは暗いテーマ用です。android:background = "?attr / colorPrimary"を追加する場合、なんらかのセレクターを使用する必要があります。
lgallard

多くのテーマがあり、そのコードのみを使用しています。このアプリを見てください:play.google.com/store/apps/...を
JavierSegoviaCordoba

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

切り替えスタイルを説明する以前の回答はすでにあるようです。どのような状況であなたの答えはそれらより適切ですか?そして明確に言うと、「実行時に、ユーザーは#ccffffを原色として使用することを決定します。もちろん、すべての可能な色のテーマを作成する方法はありません。」これはその必要性を解決しません。ただし、これを行う方法を誰も説明していなかった場合は、知っておくと役に立ちます。
ToolmakerSteve


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

出典:

これを行うための情報がここに見つかりました:Androidツールバーのアイコンの色を動的に変更する方法

それから私はそれを編集して改良し、ここに投稿しました:GitHub:AndroidDynamicToolbarItemColor


これは質問の答えにはなりません。特に、「私の目標は、最終的にはActionBar と、CheckBoxのようなすべてのウィジェットがこの原色を使用するようにすることです。」という部分です。
nhaarman

次に、追加してチェックボックスを含めます。たとえば、if(v instanceof CheckBox){themeChexnoxWithColor(toolbarIconsColor)を追加します。これがどのようにあなたの質問に正直に答えないのか分かりません
マイケル・カーン

@nhaarmanあなたはこのように動的にアクションバーの色を設定できますstackoverflow.com/questions/23708637/change-actionbar-background-color-dynamically私はちょうどあなたの質問を正確に理解していません
Michael Kern

ユーザーがアクションバーの色とアクションバーのアイテムの色を選択できるアプリを持っています。私はあなたが他に何を必要としているのか分かりません
マイケル・カーン

2
これはとても役に立ちました。
Firefly

-6

これはあなたができることです:

ドローアブルフォルダーにファイルを書き込み、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"

テーマを設定すると、この色は同じになります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.