如果希望在运行时对基础资源动态改变颜色,避免重复仅在颜色方面有所变化的常见资源。则可以使用颜色滤镜,对任意 Drawable 实例应用颜色遮罩。
Drawable 颜色滤镜通常是完全不透明的,但 Android 框架还支持通过 PorterDuff.XferMode 进行部分混合。只可以从 Java 代码中执行此方法。
下面的是没有加颜色滤镜时的输出:
下面是加了颜色滤镜后的输出 :
content_main.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:padding="8dp"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context="com.crazy.colorfilters.MainActivity"
tools:showIn="@layout/activity_main">
<ImageView
android:id="@+id/icon_marker"
android:layout_weight="1"
android:src="@drawable/eqc"
android:layout_width="0dp"
android:layout_height="wrap_content" />
<ImageView
android:id="@+id/icon_gtx"
android:layout_weight="1"
android:src="@drawable/gtx"
android:layout_width="0dp"
android:layout_height="wrap_content" />
<ImageView
android:id="@+id/icon_lik"
android:layout_weight="1"
android:src="@drawable/epr"
android:layout_width="0dp"
android:layout_height="wrap_content" />
<ImageView
android:id="@+id/icon_mvh"
android:layout_weight="1"
android:src="@drawable/lre"
android:layout_width="0dp"
android:layout_height="wrap_content" />
</LinearLayout>
ColorFilterActivity.java :
package com.crazy.colorfilters;
import android.graphics.PorterDuff;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.widget.ImageView;
public class ColorFilterActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.content_main);
applyIconFilters();
}
private void applyIconFilters(){
ImageView iconView = (ImageView)findViewById(R.id.icon_marker);
// 绘制纯紫色图标
iconView.getDrawable().mutate().setColorFilter(0xFFAA00AA, PorterDuff.Mode.SRC_ATOP);
iconView = (ImageView)findViewById(R.id.icon_gtx);
// 绘制纯绿色图标
iconView.getDrawable().mutate().setColorFilter(0xFF00AA00, PorterDuff.Mode.SRC_ATOP);
iconView = (ImageView)findViewById(R.id.icon_lik);
// 绘制纯蓝色图标(部分透明)
iconView.getDrawable().mutate().setColorFilter(0xFF0000AA, PorterDuff.Mode.MULTIPLY);
iconView = (ImageView)findViewById(R.id.icon_mvh);
// 绘制纯红色图标(部分透明)
iconView.getDrawable().mutate().setColorFilter(0xFFAA0000, PorterDuff.Mode.MULTIPLY);
}
}
使用 setColorFilter() 方法,可以通过色调绘制任何 Drawable 。该方法可以接受 ARGB 颜色值和 PorterDuff.Mode 以进行像素变换和混合。选择 SRC_ATOP 确保完全绘制所选的颜色并忽略原始的图片像素。
如果基础图片存在要露出来的变化情况(如渐变),可以取部分透明地滤镜颜色和/或者尝试使用不同的 PorterDuff.Mode 值,如上面的 MULTIPLY。
如果在同一个 Activity 中(例如在列表中)多次重复使用相同的图片资源,并且尝试设置多个色调值,就会发现所有 Drawable 将仅显示最近设置的颜色。这是因为存在所谓的共享恒定状态。因为这样可以节约内存资源。然而,这种假设的负面效果就是更改某个 Drawable 状态的属性也会影响所有其他的 Drawable 。为避免出现这种问题,在进行影响单个 Drawable 状态的修改时,都应首先调用其 mutate() 方法。如代码所示。
注意:Drawable 通常只可变化一次,因此最好不要将此方法用作复制或者克隆机制。
从 Android5.0 开始,可以使用 android:tint 属性或者在代码中通过 setTint() 方法,从 XML 中将相同的效果应用于多个 Drawable。代码如下:
在 res/drawable 目录下:
tinted_marker.xml :
<?xml version="1.0" encoding="utf-8"?>
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
android:src="@drawable/eqc"
android:tint="#FFAA00AA"/>
tinted_gtx.xml :
<?xml version="1.0" encoding="utf-8"?>
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
android:src="@drawable/gtx"
android:tint="#FF00AA00">
</bitmap>
tinted_epr.xml :
<?xml version="1.0" encoding="utf-8"?>
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
android:src="@drawable/epr"
android:tint="#FF0000AA">
</bitmap>
tinted_lre :
<?xml version="1.0" encoding="utf-8"?>
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
android:src="@drawable/lre"
android:tint="#FFAA0000">
</bitmap>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:padding="8dp"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context="com.crazy.colorfilters.MainActivity"
tools:showIn="@layout/activity_main">
<ImageView
android:id="@+id/icon_marker"
android:layout_weight="1"
android:src="@drawable/tinted_marker"
android:layout_width="0dp"
android:layout_height="wrap_content" />
<ImageView
android:id="@+id/icon_gtx"
android:layout_weight="1"
android:src="@drawable/tinted_gtx"
android:layout_width="0dp"
android:layout_height="wrap_content" />
<ImageView
android:id="@+id/icon_lik"
android:layout_weight="1"
android:src="@drawable/tinted_epr"
android:layout_width="0dp"
android:layout_height="wrap_content" />
<ImageView
android:id="@+id/icon_mvh"
android:layout_weight="1"
android:src="@drawable/tinted_lre"
android:layout_width="0dp"
android:layout_height="wrap_content" />
</LinearLayout>
ColorFilterActivity.java :
package com.crazy.colorfilters;
import android.graphics.PorterDuff;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.widget.ImageView;
public class ColorFilterActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.content_main);
// applyIconFilters();
}
/* private void applyIconFilters(){
ImageView iconView = (ImageView)findViewById(R.id.icon_marker);
// 绘制纯紫色图标
iconView.getDrawable().mutate().setColorFilter(0xFFAA00AA, PorterDuff.Mode.SRC_ATOP);
iconView = (ImageView)findViewById(R.id.icon_gtx);
// 绘制纯绿色图标
iconView.getDrawable().mutate().setColorFilter(0xFF00AA00, PorterDuff.Mode.SRC_ATOP);
iconView = (ImageView)findViewById(R.id.icon_lik);
// 绘制纯蓝色图标(部分透明)
iconView.getDrawable().mutate().setColorFilter(0xFF0000AA, PorterDuff.Mode.MULTIPLY);
iconView = (ImageView)findViewById(R.id.icon_mvh);
// 绘制纯红色图标(部分透明)
iconView.getDrawable().mutate().setColorFilter(0xFFAA0000, PorterDuff.Mode.MULTIPLY);
}*/
}
因为不在有之前应用于滤镜的 Java 代码,所以效果如下: