使用 Palette 支持包分析图片的像素数据,并为旨在补充此图片的背景和文本产生颜色样本。
调色板仅作为 Android 支持库中的模块提供,它不是核心框架的一部分。然而,目标平台为 API Level 7或之后版本的任意应用程序都可以通过包含支持库使用调色板。可以把 V7 支持库中的关于 palette 的 jar 包拷贝到应用程序中的 libs 包下。
效果如下:
item_list.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/root"
android:padding="16dp">
<ImageView
android:id="@+id/image"
android:scaleType="centerCrop"
android:layout_width="match_parent"
android:layout_height="102dp" />
<TextView
android:id="@+id/text"
android:gravity="center"
android:textAppearance="?android:textAppearanceLarge"
android:layout_width="match_parent"
android:layout_height="72dp" />
</LinearLayout>
ColorfulAdapter.java :
package com.crazy.colorfilters;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.os.AsyncTask;
import android.support.v7.graphics.Palette;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
/**
* Created by antimage on 2015/12/27.
*/
public class ColorfulAdapter extends ArrayAdapter<String> {
private static final int[] IMAGES = {
R.drawable .bricks, R.drawable.flower, R.drawable.grass,
R.drawable.stones, R.drawable.wood, R.drawable.dog
};
private static final String[] NAMES = {"砖", "花", "草", "石", "木", "狗"};
private SparseArray<Bitmap> mImages;
private SparseArray<Palette.Swatch> mBackgroundColors;
public ColorfulAdapter(Context context) {
super(context, R.layout.item_list, NAMES);
mImages = new SparseArray<>(IMAGES.length);
mBackgroundColors = new SparseArray<>(IMAGES.length);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = LayoutInflater.from(getContext())
.inflate(R.layout.item_list, parent, false);
}
View root = convertView.findViewById(R.id.root);
ImageView image = (ImageView)convertView.findViewById(R.id.image);
TextView text = (TextView)convertView.findViewById(R.id.text);
int imageId = IMAGES[position];
if (mImages.get(imageId) == null) {
new ImageTask().execute(imageId);
text.setTextColor(Color.BLACK);
} else {
image.setImageBitmap(mImages.get(imageId));
Palette.Swatch colors = mBackgroundColors.get(imageId);
if (colors != null) {
root.setBackgroundColor(colors.getRgb());
text.setTextColor(colors.getTitleTextColor());
}
}
text.setText(NAMES[position]);
return convertView;
}
private class ImageResult {
public int imageId;
public Bitmap image;
public Palette.Swatch colors;
public ImageResult(int imageId, Bitmap image, Palette.Swatch colors) {
this.imageId = imageId;
this.image = image;
this.colors = colors;
}
}
private void updateImageItem(ImageResult result) {
mImages.put(result.imageId, result.image);
mBackgroundColors.put(result.imageId, result.colors);
}
private class ImageTask extends AsyncTask<Integer, Void, ImageResult> {
@Override
protected ImageResult doInBackground(Integer... params) {
int imageId = params[0];
// 确保图片缩略图不会太大
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 4;
Bitmap image = BitmapFactory.decodeResource(
getContext().getResources(), imageId, options);
Palette colors = Palette.generate(image);
Palette.Swatch selected = colors.getVibrantSwatch();
if (selected == null) {
selected = colors.getMutedSwatch();
}
return new ImageResult(imageId, image, selected);
}
@Override
protected void onPostExecute(ImageResult result) {
updateImageItem(result);
notifyDataSetChanged();
}
}
}
在适配器的 getView() 回调中,可以看到文本颜色和背景容器颜色都从 Palette.Swatch 中读取,Palette.Swatch 可能已经存在,也可能还不存在。
因为从磁盘加载图片和使用 Palette 分析这些图片的过程会花费一些时间,所以我们要在后台执行此工作以避免阻塞主线程太长时间,所以将工作封装在 AsyncTask 中。
后台加载的结果存储在一对 SparseArray 实例中。当适配器在没有产生结果的情况下遇到一个图片条目时,它会触发新的后台任务以加载内容。通过 BitmapFactory 解码图片之后,可以使用 Palette.Generate() 收集颜色方案数据,该方法将在分析图片时阻塞。
如果在生成颜色方案时未准备好后台线程, Palette 的 generateAsync() 方法会接受回调。
完成上述操作后,可以使用各种 getter 方法访问颜色样本。首先尝试使用 getVibrantSwatch() 获取 Vibrant 样本。如果图片颜色不兼容 Vibrant 颜色方案(即返回 null),我们就降低要求,获取一种颜色减弱的样本。
解码的图片和选择的样本封装在持有者对象(ImageResult)中,这样有助于从 AsyncTask 返回多个条目,AsyncTask 仅支持返回单个类型。
ColorfulListActivity.java :
package com.crazy.colorfilters;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.widget.GridView;
public class ColorfulListActivity extends ActionBarActivity {
private GridView mGridView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mGridView = new GridView(this);
mGridView.setNumColumns(2);
mGridView.setAdapter(new ColorfulAdapter(this));
setContentView(mGridView);
}
}