一、常见问题
圆形ImageView是Android开发中比较常见的一个需求,但是Android原生的ImageView并不支持直接绘制圆形,所以需要使用自定义View。
下面是一些常见问题:
1、怎样绘制一个圆形ImageView?
2、怎样使圆形ImageView具有边框?
3、怎样对圆形ImageView进行动画操作?
二、原理与实现
绘制一个圆形的ImageView可以分为以下几步:
1、继承ImageView
2、重写onDraw方法,在其中绘制一个圆形的Bitmap
3、设置ImageView的ScaleType为CENTER_CROP,保证图片的宽高比被保持且填充满整个View
4、可以根据需求在绘制的Bitmap周围添加边框或者做动画效果
下面是代码示例:
public class CircleImageView extends ImageView { private Bitmap mBitmap; private Paint mPaint; public CircleImageView(Context context) { super(context); init(); } public CircleImageView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public CircleImageView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setShader(new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)); } @Override protected void onDraw(Canvas canvas) { Drawable drawable = getDrawable(); if (drawable == null) { super.onDraw(canvas); } else { mBitmap = drawableToBitmap(drawable); mPaint.setShader(new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)); canvas.drawCircle(getWidth() / 2, getHeight() / 2, getWidth() / 2, mPaint); } } private Bitmap drawableToBitmap(Drawable drawable) { if (drawable instanceof BitmapDrawable) { return ((BitmapDrawable) drawable).getBitmap(); } int width = drawable.getIntrinsicWidth(); int height = drawable.getIntrinsicHeight(); Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); drawable.draw(canvas); return bitmap; } }
三、常用功能实现
1、添加边框
在上面的代码基础上,我们可以在绘制Bitmap的周围添加一些边框来增强视觉效果。
下面是添加边框的代码示例:
public class CircleImageView extends ImageView { private Bitmap mBitmap; private Paint mPaint; private Paint mBorderPaint; private int mBorderColor; private int mBorderWidth; public CircleImageView(Context context) { super(context); init(); } public CircleImageView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public CircleImageView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircleImageView, defStyleAttr, 0); mBorderColor = a.getColor(R.styleable.CircleImageView_borderColor, Color.WHITE); mBorderWidth = a.getDimensionPixelSize(R.styleable.CircleImageView_borderWidth, 0); a.recycle(); init(); } private void init() { mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setShader(new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)); mBorderPaint = new Paint(); mBorderPaint.setAntiAlias(true); mBorderPaint.setColor(mBorderColor); mBorderPaint.setStyle(Paint.Style.STROKE); mBorderPaint.setStrokeWidth(mBorderWidth); } @Override protected void onDraw(Canvas canvas) { Drawable drawable = getDrawable(); if (drawable == null) { super.onDraw(canvas); } else { mBitmap = drawableToBitmap(drawable); mPaint.setShader(new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)); canvas.drawCircle(getWidth() / 2, getHeight() / 2, getWidth() / 2 - mBorderWidth, mPaint); canvas.drawCircle(getWidth() / 2, getHeight() / 2, getWidth() / 2 - mBorderWidth / 2, mBorderPaint); } } private Bitmap drawableToBitmap(Drawable drawable) { if (drawable instanceof BitmapDrawable) { return ((BitmapDrawable) drawable).getBitmap(); } int width = drawable.getIntrinsicWidth(); int height = drawable.getIntrinsicHeight(); Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); drawable.draw(canvas); return bitmap; } }
2、添加动画
我们也可以为这个圆形ImageView添加一些动画效果,比如旋转、缩放、渐变等。
下面是旋转动画和缩放动画的代码示例:
public class CircleImageView extends ImageView { private Bitmap mBitmap; private Paint mPaint; private Matrix mMatrix; private float mRotation; private float mScale = 1f; public CircleImageView(Context context) { super(context); init(); } public CircleImageView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public CircleImageView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setShader(new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)); mMatrix = new Matrix(); } @Override protected void onDraw(Canvas canvas) { Drawable drawable = getDrawable(); if (drawable == null) { super.onDraw(canvas); } else { mBitmap = drawableToBitmap(drawable); mPaint.setShader(new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)); int width = getWidth(); int height = getHeight(); int size = Math.min(width, height); mMatrix.reset(); mMatrix.postScale(mScale, mScale); mMatrix.postRotate(mRotation, size / 2f, size / 2f); mMatrix.postTranslate((width - size) / 2f, (height - size) / 2f); canvas.drawCircle(size / 2f, size / 2f, size / 2f, mPaint); } } public void setRotation(float rotation) { mRotation = rotation; invalidate(); } public void setScale(float scale) { mScale = scale; invalidate(); } public void rotate(float from, float to, long duration) { ObjectAnimator animator = ObjectAnimator.ofFloat(this, "rotation", from, to); animator.setDuration(duration); animator.start(); } public void scale(float from, float to, long duration) { ValueAnimator animator = ValueAnimator.ofFloat(from, to); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { mScale = (float) animation.getAnimatedValue(); invalidate(); } }); animator.setDuration(duration); animator.start(); } private Bitmap drawableToBitmap(Drawable drawable) { if (drawable instanceof BitmapDrawable) { return ((BitmapDrawable) drawable).getBitmap(); } int width = drawable.getIntrinsicWidth(); int height = drawable.getIntrinsicHeight(); Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); drawable.draw(canvas); return bitmap; } }