Android自定义View实现圆形切图效果

2020-10-26 22:28:57 浏览数 (3)

使用自定义View实现圆形ImageView的效果,具体内容如下

目前圆形边框还需要调整,这里有点问题

实现思路

使用一个Paint,将得到的Bitmap设置成paint的Shader,设置完成后,使用Matrix调整图片至居中,使用RectF约束边框,最后完成绘制

初始化Paint,设置Shader

代码语言:javascript复制
private void init() {
  getBitmapFromDrawable();
  if (mBitmap == null) {
   return;
  }
  mShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);

  // bitmap paint
  mFillPaint = new Paint();
  mFillPaint.setAntiAlias(true);
  mFillPaint.setStyle(Paint.Style.FILL);
  mFillPaint.setShader(mShader);

  // border paint
  mBoundPaint = new Paint();
  mBoundPaint.setAntiAlias(true);
  mBoundPaint.setStyle(Paint.Style.STROKE);
  mBoundPaint.setStrokeWidth(mBorderWidth);
  mBoundPaint.setColor(mBorderColor);

  // border rectF
  mBorderBound.set(calculateBitmapBound());

  // bitmap rectF
  mBitmapBound.set(calculateBitmapBound());
  mBitmapBound.inset(mBorderWidth - 10, mBorderWidth - 10);
  updateShaderMatrix();

 }

获取Drawable

代码语言:javascript复制
private Bitmap getBitmapFromDrawable() {
  Drawable drawable = getDrawable();
  if (drawable instanceof BitmapDrawable) {
   mBitmap = ((BitmapDrawable) drawable).getBitmap();
   mBitmapWidth = mBitmap.getWidth();
   mBitmapHeight = mBitmap.getHeight();
   return mBitmap;
  }
  return null;
 }

计算边距

代码语言:javascript复制
 /**
  * 计算Bitmap边距
  */
 private RectF calculateBitmapBound() {
  int availableWidth = getWidth() - getPaddingLeft() - getPaddingRight();
  int availableHeight = getHeight() - getPaddingTop() - getPaddingBottom();
  int sideLength = Math.min(availableWidth, availableHeight); // 可用的直径
  mRadius = sideLength / 2;

  int left = getPaddingLeft()   (availableWidth - sideLength) / 2;
  int top = getPaddingTop()   (availableHeight - sideLength) / 2;

  Log.d(TAG, "calculateBitmapBound: left     "   left   " top     "   top   " right     "
      (left   sideLength)   " right     "   top   " bottom     "   (top   sideLength));
  return new RectF(left, top, left   sideLength, top   sideLength);
 }

调整Matrix,防止只显示图片边角

代码语言:javascript复制
 /**
  * 调整图片缩放,目前只支持CenterCrop
  */
 private void updateShaderMatrix() {
  float scale;
  float dx = 0;
  float dy = 0;

  mShaderMatrix.set(null);

  // 调整缩放,使图片居中
  if (mBitmapWidth * mBitmapBound.height()   mBitmapBound.width() * mBitmapHeight) {
   scale = mBitmapBound.height() / (float) mBitmapHeight;
   dx = (mBitmapBound.width() - mBitmapWidth * scale) * 0.5f;
  } else {
   scale = mBitmapBound.width() / (float) mBitmapWidth;
   dy = (mBitmapBound.height() - mBitmapHeight * scale) * 0.5f;
  }

  Log.d(TAG, "updateShaderMatrix: scale     "   scale);
  mShaderMatrix.setScale(scale, scale);
  // TODO: 16-10-15 http://chroya.iteye.com/blog/713869
  // 回到中心点,便于下次缩放
  mShaderMatrix.postTranslate((int) (dx   0.5f)   mBitmapBound.left, (int) (dy   0.5f)   mBitmapBound.top);

  mShader.setLocalMatrix(mShaderMatrix);
 }

onDraw

代码语言:javascript复制
 @Override
 protected void onDraw(Canvas canvas) {
  if (mBitmap == null) {
   super.onDraw(canvas);
  }
  Log.d(TAG, "onDraw: centerX     "   mBitmapBound.centerX()   " centerY     "   mBitmapBound.centerY());
  canvas.drawCircle(mBitmapBound.centerX(), mBitmapBound.centerY(), mRadius, mFillPaint);
  // 绘制边框
  canvas.drawCircle(mBorderBound.centerX(), mBorderBound.centerY(), mRadius, mBoundPaint);
 }

完整代码

代码语言:javascript复制
/**
* Created by shixi_tianrui1 on 16-10-7.
* 显示圆形图片的ImageView
*/
public class CircleImageView extends ImageView {
private static final String TAG = "LOGGER";
private BitmapShader mShader;
private Paint mFillPaint; // 绘图
private Paint mBoundPaint; // 绘制圆边
private Bitmap mBitmap;
private Drawable mDrawable;
private int mBorderColor;  // 边框颜色
private float mBorderWidth;  // 边框宽度
private RectF mBorderBound = new RectF();
private RectF mBitmapBound = new RectF();
private Matrix mShaderMatrix = new Matrix();
private int mRadius;
private int mBitmapWidth;
private int mBitmapHeight;
private static final float DEFAULT_BORDER_WIDTH = 5;
public CircleImageView(Context context) {
this(context, null);
}
public CircleImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CircleImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray a = getResources().obtainAttributes(attrs, R.styleable.CircleImageView);
mBorderColor = a.getColor(R.styleable.CircleImageView_borderColor, Color.BLUE);
mBorderWidth = a.getDimension(R.styleable.CircleImageView_borderWidth, DEFAULT_BORDER_WIDTH);
mBorderWidth = a.getDimensionPixelSize(R.styleable.CircleImageView_borderWidth, 20);
a.recycle();
}
private void init() {
getBitmapFromDrawable();
if (mBitmap == null) {
return;
}
mShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
// bitmap paint
mFillPaint = new Paint();
mFillPaint.setAntiAlias(true);
mFillPaint.setStyle(Paint.Style.FILL);
mFillPaint.setShader(mShader);
// border paint
mBoundPaint = new Paint();
mBoundPaint.setAntiAlias(true);
mBoundPaint.setStyle(Paint.Style.STROKE);
mBoundPaint.setStrokeWidth(mBorderWidth);
mBoundPaint.setColor(mBorderColor);
// border rectF
mBorderBound.set(calculateBitmapBound());
// bitmap rectF
mBitmapBound.set(calculateBitmapBound());
mBitmapBound.inset(mBorderWidth - 10, mBorderWidth - 10);
updateShaderMatrix();
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
init();
}
/**
* 计算Bitmap边距
*/
private RectF calculateBitmapBound() {
int availableWidth = getWidth() - getPaddingLeft() - getPaddingRight();
int availableHeight = getHeight() - getPaddingTop() - getPaddingBottom();
int sideLength = Math.min(availableWidth, availableHeight); // 可用的直径
mRadius = sideLength / 2;
int left = getPaddingLeft()   (availableWidth - sideLength) / 2;
int top = getPaddingTop()   (availableHeight - sideLength) / 2;
Log.d(TAG, "calculateBitmapBound: left     "   left   " top     "   top   " right     "
  (left   sideLength)   " right     "   top   " bottom     "   (top   sideLength));
return new RectF(left, top, left   sideLength, top   sideLength);
}
private Bitmap getBitmapFromDrawable() {
Drawable drawable = getDrawable();
if (drawable instanceof BitmapDrawable) {
mBitmap = ((BitmapDrawable) drawable).getBitmap();
mBitmapWidth = mBitmap.getWidth();
mBitmapHeight = mBitmap.getHeight();
return mBitmap;
}
return null;
}
@Override
protected void onDraw(Canvas canvas) {
if (mBitmap == null) {
super.onDraw(canvas);
}
Log.d(TAG, "onDraw: centerX     "   mBitmapBound.centerX()   " centerY     "   mBitmapBound.centerY());
canvas.drawCircle(mBitmapBound.centerX(), mBitmapBound.centerY(), mRadius, mFillPaint);
// 绘制边框
canvas.drawCircle(mBorderBound.centerX(), mBorderBound.centerY(), mRadius, mBoundPaint);
}
/**
* 调整图片缩放,目前只支持CenterCrop
*/
private void updateShaderMatrix() {
float scale;
float dx = 0;
float dy = 0;
mShaderMatrix.set(null);
// 调整缩放,使图片居中
if (mBitmapWidth * mBitmapBound.height()   mBitmapBound.width() * mBitmapHeight) {
scale = mBitmapBound.height() / (float) mBitmapHeight;
dx = (mBitmapBound.width() - mBitmapWidth * scale) * 0.5f;
} else {
scale = mBitmapBound.width() / (float) mBitmapWidth;
dy = (mBitmapBound.height() - mBitmapHeight * scale) * 0.5f;
}
Log.d(TAG, "updateShaderMatrix: scale     "   scale);
mShaderMatrix.setScale(scale, scale);
// TODO: 16-10-15 http://chroya.iteye.com/blog/713869
// 回到中心点,便于下次缩放
mShaderMatrix.postTranslate((int) (dx   0.5f)   mBitmapBound.left, (int) (dy   0.5f)   mBitmapBound.top);
mShader.setLocalMatrix(mShaderMatrix);
}
}

目前仍有点问题,解决后会及时更新。

以上就是本文的全部内容,希望对大家的学习有所帮助。

0 人点赞