圆形自定义ImageView的简单制作

很多微博,社交APP的个人资料里面的人物头像都是圆形的。有两种办法,一种是图片本身是圆形的,另一种则是ImageView在绘制图片时将图片裁剪成了圆形。第一种做法没什么好说的,来看看第二种是如何做到的。

在网上看了一下相关代码,发现很多都挺复杂的,各种情况的考虑以及自定义属性等等,我在这里将核心代码提炼了一下,归结出一套比较简单的写法,思路很清晰,适合新手学习。

既然是自定义圆形ImageView,那么肯定要继承一个ImageView。可以分成以下几个步骤:

1.确定圆的直径:在onMeare()中测量控件的宽高,选择短的那一边作为圆的直径。

2.确定圆心位置:控件宽/2,控件高/2

3.缩放图片,使得图片正好能填充进这个圆形中:给paint设置一个渲染器,渲染器中加载一个变换矩阵。缩放的倍数应该怎么选择呢?我觉得比较好的一种方式是控件短的那一边(圆的直径)除以图片短的那一边。这里以图片大小小于控件为基础来解释为什么是除以图片短的那一边而不是长的那一边:如果除以图片长的一边,那么图片放大后,长的一边与圆形正好吻合,而短的一边比圆的直径要小,渲染器的特点是以坐上角为基点放大,未填充满的部分就会无限重复最后一点的像素,这是一种很恐怖的现象,下面会给出图片给大家看看。反之,如果是圆的直径除以图片短的一边,这样虽然会使得放大倍数较大,图片裁剪较多,但也要比前一种情况好点。

4.最后用canvas的drawCircle方法绘制圆形:drawCircle(cx, cy, radius, paint),前两个参数是圆心位置,第三个参数是半径,第四个参数是增加了渲染器的画笔,这几个参数在上述步骤中都已经实现了。经过这几步分析,相信大家对自定义圆形ImageView有了一点底了吧。下面给出代码和效果图:

CircleImageView.java:

package com.xiaoteng.dms.component;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Shader.TileMode;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.ImageView;

public class CircleImageView extends ImageView {
	private int viewHeight, viewWidth;// 控件宽高
	private int imageHeight, imageWidth;// 图片宽高
	private int mWidth, radius, mSize;// 圆形控件的直径,半径;位图直径
	private Paint paint;// 画笔
	private Bitmap bitmap;// 位图
	private float mScale;// 缩放比例
	private Matrix matrix;// 变换矩阵
	private BitmapShader shader;// 渲染器
	private Canvas mCanvas;//画布

	public CircleImageView(Context context) {
		super(context);
		// TODO Auto-generated constructor stub
	}

	public CircleImageView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		// TODO Auto-generated constructor stub
	}

	public CircleImageView(Context context, AttributeSet attrs) {
		super(context, attrs);
		// TODO Auto-generated constructor stub
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		// TODO Auto-generated method stub
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		viewHeight = getMeasuredHeight();
		viewWidth = getMeasuredHeight();
		mWidth = Math.max(viewHeight, viewWidth);
		radius = mWidth / 2;
	}

	@Override
	protected void onDraw(Canvas canvas) {
//		 super.onDraw(canvas);
		// TODO Auto-generated method stub
		mCanvas = canvas;
		if (null == getDrawable()) {
			return;
		}
		setBitmapShader();
		// 前两个参数:圆心坐标
		canvas.drawCircle(getMeasuredWidth() / 2, getMeasuredHeight() / 2, radius, paint);
	}
	/**
	 * 设置渲染器
	 */
	private void setBitmapShader() {
		Drawable drawable = getDrawable();
		Log.i("info>", "circleDrawable>"+drawable);
		if (null == drawable) {
			return;
		}
		drawableToBitamp(drawable);
		mScale = 1.0f;
		// 初始化
		shader = new BitmapShader(bitmap, TileMode.CLAMP, TileMode.CLAMP);
		matrix = new Matrix();
		paint = new Paint();

		mSize = Math.min(bitmap.getHeight(), bitmap.getWidth());
		mScale = mWidth * 1.0f / mSize;
		// 变换矩阵
		// matrix.setScale(0, 0, mScale, mScale);
		matrix.setScale(mScale, mScale);
		// 设置渲染器
		shader.setLocalMatrix(matrix);
		// 设置画笔
		paint.setShader(shader);

	}

	private void drawableToBitamp(Drawable drawable) {
		BitmapDrawable bd = (BitmapDrawable) drawable;
		bitmap = bd.getBitmap();
	}

}

main.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <com.example.circleimageviewtest.CircleImageView
        android:id="@+id/image1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/course_collection" />
</RelativeLayout>

下面是效果图:

看下面那种情况,就是不断重复最后一个像素点,所以我还是推荐用上面那一种情况。ok了,自定义圆形控件完成了,下面给一个github上大神写的比较完善的CircleImageView的链接:

https://github.com/hdodenhof/CircleImageView

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值