package com.mcxtzhang.cstviewdemo.widget;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;
import java.util.Arrays;
/**
* 项目名称:CircleImageView
* 类描述:
* 创建人:zuowei
* 创建时间:16-11-14 上午10:35
* 修改人:zuowei
* 修改时间:16-11-14 上午10:35
* 修改备注:
*/
public class CircleImageView extends ImageView {
float radius;
Path circlePath;
Paint paint;
Paint layerPaint;
RectF layerRect;
PorterDuffXfermode porterDuffXfermode;
boolean drawableSettled;
volatile boolean isDirty;
public CircleImageView(Context context) {
super(context);
}
public CircleImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CircleImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
{
init();
}
private void init() {
circlePath = new Path();
paint = new Paint();
layerPaint = new Paint();
layerPaint.setXfermode(null);
layerRect = new RectF();
porterDuffXfermode = new PorterDuffXfermode(PorterDuff.Mode.DST_IN);
paint.setAntiAlias(true);
paint.setXfermode(porterDuffXfermode);
addOnLayoutChangeListener(new OnLayoutChangeListener() {
@Override
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
removeOnLayoutChangeListener(this);
isDirty = true;
}
});
}
private boolean syncDrawable() {
Drawable drawable = getDrawable();
if (drawable != null) {
layerRect.set(getPaddingLeft(), getPaddingTop(), getWidth() - getPaddingRight(), getHeight() - getPaddingBottom());
Rect bounds = drawable.getBounds();
int vwidth = getWidth() - getPaddingLeft() - getPaddingRight();
int vheight = getHeight() - getPaddingTop() - getPaddingBottom();
float[] scaleParams = getScaleParams();
if (scaleParams != null && !bounds.isEmpty()) {
radius = min(vwidth / 2f, vheight / 2f, bounds.centerX() * scaleParams[0], bounds.centerY() * scaleParams[1]);
} else {
radius = min(vwidth / 2f, vheight / 2f);
}
if (getScaleType() == ScaleType.MATRIX) {
setImageMatrix(getNewMatrix(bounds.left, bounds.top, bounds.right, bounds.bottom));//support matrix
}
return true;
}
return false;
}
private void syncDrawableIf() {
drawableSettled = syncDrawable();
}
private float[] getScaleParams() {
Matrix imageMatrix = getImageMatrix();
float[] martixValues = new float[9];
imageMatrix.getValues(martixValues);
if (martixValues[0] == 0 || martixValues[4] == 0)
return null;
return new float[]{martixValues[0], martixValues[4]};
}
@Override
public void setBackground(Drawable background) {
setImageDrawable(background);
}
@Override
public void setBackgroundColor(int color) {
setBackground(new ColorDrawable(color));
}
@Override
public void setBackgroundDrawable(Drawable background) {
setBackground(background);
}
@Override
public void setScaleType(ScaleType scaleType) {
super.setScaleType(scaleType);
}
@Override
protected void onDraw(Canvas canvas) {
syncDrawableIf();
if (drawableSettled) {
int layerID = canvas.saveLayer(layerRect, layerPaint, Canvas.CLIP_SAVE_FLAG);//clear background
/*
circlePath.reset();
circlePath.addCircle(layerRect.centerX(), layerRect.centerY(), radius, Path.Direction.CCW);
canvas.clipPath(circlePath);*/
super.onDraw(canvas);//draw drawable
circlePath.reset();
circlePath.addCircle(layerRect.centerX(), layerRect.centerY(), radius - 1f, Path.Direction.CCW);//Antialiasing
canvas.drawPath(circlePath, paint);
canvas.restoreToCount(layerID);
} else {
super.onDraw(canvas);
}
}
private Matrix getNewMatrix(int left, int top, int right, int bottom) {
float scale;
float dx = 0;
float dy = 0;
int vwidth = getWidth() - getPaddingLeft() - getPaddingRight();
int vheight = getHeight() - getPaddingTop() - getPaddingBottom();
int width = right - left;
int height = bottom - top;
Matrix matrix = new Matrix();
matrix.set(null);
if (width * vheight > vwidth * height) {
scale = vheight / (float) height;
dx = (vwidth - width * scale) * 0.5f;
} else {
scale = vwidth / (float) height;
dy = (vheight - height * scale) * 0.5f;
}
matrix.setScale(scale, scale);
matrix.postTranslate((int) (dx + 0.5f) + left, (int) (dy + 0.5f) + top);
return matrix;
}
private float min_r(float... values) {
if (values.length == 1) {
return values[0];
}
float[] newValues = Arrays.copyOf(values, values.length - 1);
newValues[newValues.length - 1] = Math.min(values[values.length - 1], values[values.length - 2]);
return min_r(newValues);
}
private float min(float... values) {
if (values.length <= 0) {
throw new IndexOutOfBoundsException("values is empty");
}
float min = values[0];
for (float value : values) {
min = Math.min(value, min);
}
return min;
}
}