如何通过编程来改变 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一样使用这个主色调。

127140 次浏览

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

从你可以做的活动:

getWindow().setStatusBarColor(i color);

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

也许,通讯录应用程序有一些预定义的主题(每个材质的基本颜色从这里: 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>

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

使用工具栏

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

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

这就是你能做的:

在可绘制文件夹中编写一个文件,将其命名为 backound.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"

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

可以使用 主题,应用风格在运行时通过应用另一种样式来修改主题。

假设您有以下样式定义:

<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万种(2563)颜色中的一种。但是如果您编写一个小程序,为您生成样式定义和 Java 代码,那么类似于512(83)中的一个应该是可能的。

有趣的是,您可以为主题的不同方面使用不同的样式覆盖。例如,只需为 colorAccent添加一些覆盖定义。现在您可以组合不同的值为基本颜色和重音颜色 差不多任意。

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

我已经创建了一些解决方案,使任何颜色的主题,也许这可以有用的人

1. 首先创建“ Res/value-v9/”并把这个文件放在那里: 和常规的“ res/value”文件夹将与您的样式一起使用。

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. 安卓宣言:

<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. 主要活动:

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,希望这有所帮助。

enter image description here

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

你可以从 鲁米特 · 帕特尔看看这个 GitHub 项目

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

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

您可以更改定义自己的主题,或者在 res > value > theme 中自定义现有的 android 主题,找到它表示主色的位置,并将其指向所需的 color.xml 中定义的颜色

enter image description here

 <style name="Theme.HelloWorld" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<!-- Primary brand color. -->
<item name="colorPrimary">@color/my_color</item>
<item name="colorPrimaryVariant">@color/my_color</item>
<item name="colorOnPrimary">@color/white</item>