前言:
说实话,这段时间忙着修改毕业论文,好长时间没有碰代码了,真是罪过呀。今天我们就来奉上我们打造圆形ImageView的终结篇,以后如果还有新的创意再说啦。本文是在前面三篇的基础上得来的,详细请戳android自定义view-打造圆形ImageView(一)、android自定义view-打造圆形ImageView(二)、android自定义view-打造圆形ImageView(三)。
效果图:
正文:
其实看了上面的效果图,大家应该都一目了然了,就是很多应用经常见到的带有白色边缘的渐变头像ImageView。我们今天采用的就是第二篇采用的Xfermode去处理图片,其实代码都是差不多的,只要在那基础上做简单修改即可。不过,只是画了圆形的,没有圆角的...见谅哈
在我们开始之前的知识准备有哪些呢?之前给大家讲过线性渐变,然而今天我们需要用到是球型渐变RadialGradient。
android.graphics.RadialGradient.RadialGradient(float x, float y, float radius, int[] colors, float[] positions, TileMode tile)
// 创建画笔
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setDither(true);
RadialGradient gradient = new RadialGradient(getWidth() / 2, getHeight() / 2, getWidth() / 2, new int[] { 0xff5d5d5d, 0xff5d5d5d, 0x00ffffff }, new float[] { 0.f, 0.9f, 1.0f }, Shader.TileMode.CLAMP);
paint.setShader(gradient);
在绘制Mask蒙板图层的时候,即形状绘制的时候进行渐变处理,其实也很简单,没什么好解释的。
@Override
protected void onDraw(Canvas canvas) {
// 从缓存中取出图片
Bitmap bitmap = mWeakBitmap == null ? null : mWeakBitmap.get();
// 如果没有缓存或者被回收了,则重新绘制
if (bitmap == null || bitmap.isRecycled()) {
// 获取背景drawable
Drawable drawable = getDrawable();
// 如果有背景图则绘制
if (drawable != null) {
// 拿到drawable的长度和宽度
int dWidth = drawable.getIntrinsicWidth();
int dHeight = drawable.getIntrinsicHeight();
bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Config.ARGB_8888);
// 创建画布
Canvas canvas1 = new Canvas(bitmap);
// 设置图片缩放比率
float scale = 1.0f;
scale = Math.max(getWidth() * 1.0f / dWidth, getHeight() * 1.0f / dHeight);
// 缩放图片
drawable.setBounds(0, 0, (int) (scale * dWidth), (int) (scale * dHeight));
// 绘制DST图片
drawable.draw(canvas1);
// 绘制SRC图片
if (mMaskBitmap == null || mMaskBitmap.isRecycled()) {
mMaskBitmap = drawType();
}
// 重置画笔
mPaint.reset();
// 不采用滤波
mPaint.setFilterBitmap(false);
mPaint.setXfermode(xfermode);
canvas1.drawBitmap(mMaskBitmap, 0, 0, mPaint);
Paint paint1 = new Paint(Paint.ANTI_ALIAS_FLAG);
paint1.setColor(0xffffffff);
paint1.setStrokeWidth(mGradientBorder);
paint1.setStyle(Paint.Style.STROKE);
paint1.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
canvas1.drawCircle(getWidth() / 2, getHeight() / 2, getWidth() / 2 - mGradientGap, paint1);
// drawable.draw(canvas);
// 绘制处理好的图形
mPaint.setXfermode(null);
canvas.drawBitmap(bitmap, 0, 0, mPaint);
// 缓存图片
mWeakBitmap = new WeakReference(bitmap);
}
}
if (bitmap != null) {
mPaint.setXfermode(null);
canvas.drawBitmap(bitmap, 0.0f, 0.0f, mPaint);
}
}
这里唯一的区别就是在canvas.drawBitmap(bitmap,0,0,mPaint)之前需要进行白色边缘处理,说白了,就是再加一个步骤啦。
Paint paint1 = new Paint(Paint.ANTI_ALIAS_FLAG);
paint1.setColor(0xffffffff);
paint1.setStrokeWidth(mGradientBorder);
paint1.setStyle(Paint.Style.STROKE);
paint1.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
canvas1.drawCircle(getWidth() / 2, getHeight() / 2, getWidth() / 2 - mGradientGap, paint1);
这段就是处理白色边缘的代码,其实也没啥好说的,至于Xfermode不懂,回头看我之前的三篇博客吧。
package com.beyole.view;
import java.lang.ref.WeakReference;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.graphics.RadialGradient;
import android.graphics.Shader;
import android.graphics.Xfermode;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.ImageView;
public class GradientImageView extends ImageView {
// 白色边缘大小
private int mGradientBorder = 7;
// 设置白色边缘与渐变间距
private int mGradientGap = 5;
// 画笔
private Paint mPaint;
// 使用缓存机制来保存处理好的bitmap,便于GC
private WeakReference mWeakBitmap;
// 设置Xfermode的模式为DST_IN
private Xfermode xfermode = new PorterDuffXfermode(Mode.DST_IN);
// 蒙板图层
private Bitmap mMaskBitmap;
public GradientImageView(Context context) {
this(context, null);
}
public GradientImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public GradientImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// 初始化画笔
mPaint = new Paint();
mPaint.setAntiAlias(true);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// 强制宽高一致,以最小的值为准
int mWidth = Math.min(getMeasuredWidth(), getMeasuredHeight());
setMeasuredDimension(mWidth, mWidth);
}
@Override
protected void onDraw(Canvas canvas) {
// 从缓存中取出图片
Bitmap bitmap = mWeakBitmap == null ? null : mWeakBitmap.get();
// 如果没有缓存或者被回收了,则重新绘制
if (bitmap == null || bitmap.isRecycled()) {
// 获取背景drawable
Drawable drawable = getDrawable();
// 如果有背景图则绘制
if (drawable != null) {
// 拿到drawable的长度和宽度
int dWidth = drawable.getIntrinsicWidth();
int dHeight = drawable.getIntrinsicHeight();
bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Config.ARGB_8888);
// 创建画布
Canvas canvas1 = new Canvas(bitmap);
// 设置图片缩放比率
float scale = 1.0f;
scale = Math.max(getWidth() * 1.0f / dWidth, getHeight() * 1.0f / dHeight);
// 缩放图片
drawable.setBounds(0, 0, (int) (scale * dWidth), (int) (scale * dHeight));
// 绘制DST图片
drawable.draw(canvas1);
// 绘制SRC图片
if (mMaskBitmap == null || mMaskBitmap.isRecycled()) {
mMaskBitmap = drawType();
}
// 重置画笔
mPaint.reset();
// 不采用滤波
mPaint.setFilterBitmap(false);
mPaint.setXfermode(xfermode);
canvas1.drawBitmap(mMaskBitmap, 0, 0, mPaint);
Paint paint1 = new Paint(Paint.ANTI_ALIAS_FLAG);
paint1.setColor(0xffffffff);
paint1.setStrokeWidth(mGradientBorder);
paint1.setStyle(Paint.Style.STROKE);
paint1.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
canvas1.drawCircle(getWidth() / 2, getHeight() / 2, getWidth() / 2 - mGradientGap, paint1);
// drawable.draw(canvas);
// 绘制处理好的图形
mPaint.setXfermode(null);
canvas.drawBitmap(bitmap, 0, 0, mPaint);
// 缓存图片
mWeakBitmap = new WeakReference(bitmap);
}
}
if (bitmap != null) {
mPaint.setXfermode(null);
canvas.drawBitmap(bitmap, 0.0f, 0.0f, mPaint);
}
}
/**
* 绘制形状,作为src
*
* @return
*/
private Bitmap drawType() {
Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
// 创建画笔
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setDither(true);
RadialGradient gradient = new RadialGradient(getWidth() / 2, getHeight() / 2, getWidth() / 2, new int[] { 0xff5d5d5d, 0xff5d5d5d, 0x00ffffff }, new float[] { 0.f, 0.9f, 1.0f }, Shader.TileMode.CLAMP);
paint.setShader(gradient);
canvas.drawCircle(getWidth() / 2, getWidth() / 2, getWidth() / 2, paint);
return bitmap;
}
// 在重绘中进行mask和dst的内存回收
@Override
public void invalidate() {
mWeakBitmap = null;
if (mMaskBitmap != null) {
mMaskBitmap.recycle();
mMaskBitmap = null;
}
super.invalidate();
}
// 对外公布白色边缘宽度
public void setGradientBorder(int gradientBorder) {
this.mGradientBorder = gradientBorder;
}
// 对外公布白色边缘与渐变间距
public void setGradientGap(int gradientGap) {
this.mGradientGap = gradientGap;
}
}
上面公布了两个对外方法,如果用的时候觉得丑,就重新设置一下数值就会看到意想不到的效果:
// 对外公布白色边缘宽度
public void setGradientBorder(int gradientBorder) {
this.mGradientBorder = gradientBorder;
}
// 对外公布白色边缘与渐变间距
public void setGradientGap(int gradientGap) {
this.mGradientGap = gradientGap;
}
如何使用就很简单了:
题外话:
android交流群:279031247(广告勿入)
新浪微博:SmartIceberg