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

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

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

实现思路

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

初始化Paint,设置Shader

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

private Bitmap getBitmapFromDrawable() {
  Drawable drawable = getDrawable();
  if (drawable instanceof BitmapDrawable) {
   mBitmap = ((BitmapDrawable) drawable).getBitmap();
   mBitmapWidth = mBitmap.getWidth();
   mBitmapHeight = mBitmap.getHeight();
   return mBitmap;
  }
  return null;
 }


计算边距

 /**
  * 计算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,防止只显示图片边角

 /**
  * 调整图片缩放,目前只支持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

 @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(),mBoundPaint);
 }


完整代码

/**
 * 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,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,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,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,mBoundPaint);
 }


 /**
  * 调整图片缩放,(int) (dy + 0.5f) + mBitmapBound.top);

  mShader.setLocalMatrix(mShaderMatrix);
 }
}

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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程小技巧。

相关文章

Android性能优化——之控件的优化 前面讲了图像的优化,接下...
前言 上一篇已经讲了如何实现textView中粗字体效果,里面主要...
最近项目重构,涉及到了数据库和文件下载,发现GreenDao这个...
WebView加载页面的两种方式 一、加载网络页面 加载网络页面,...
给APP全局设置字体主要分为两个方面来介绍 一、给原生界面设...
前言 最近UI大牛出了一版新的效果图,按照IOS的效果做的,页...