圆形头像的绘制

哎   我真是太伤心了,写了好久的博客,但是因为没有保存就全没有啦  重新写!!! 嚯……

圆形的图片在APP中是非常常见的,它常用来做头像,一般的ImageView是没有什么属性显示成圆形的,所以这是一个自定义控件

这篇博客是一个底层实现原理,如果嫌麻烦的话可以找一些第三方控件

既然圆形的View是一个自定义控件 ,那么自定义View的具体步骤有哪些呢~~~

请自行百度!!

(其实我还蛮想写几篇自定义View的博客的,,,如果我知道怎么写的话哈哈哈哈哈!!)

自定义这个圆形显示的View分为一下几部

1.创建自定义View继承自View,实现两个构造方法
2.为自定义View添加背景属性
3.将自定义View上的图片显示成圆形

自定义View继承View

实现两个构造方法,构造方法的作用如下

public class MyCircleImageView extends ImageView {
   //方便代码的初始化
    public MyCircleImageView(Context context) {
        super(context);
    }

    //方便在XML文件中使用
    public MyCircleImageView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);


    }
 }

为自定义View添加src属性
这里继承的是View,如果是继承自View的话,继承过来的属性只有  宽  高  背景(background)

这个background属性是填充View的背景(方形的),而我们自定义的背景属性是圆形显示的背景,不一样

这个自定义View是不带src属性的,这里呢我们为它添加一个src属性(当然既然这个控件和属性都是自定义的,名字也可以随便取了,你可以叫circleSrc)
1.在value目录之下创建下面xml文件叫 attrs.xml,里面装载着自定义控件的属性

<resources>
    <!--属性的集合,所有自定义控件的属性都会写在里面-->
    <!--name一般会和自定义控件名字一样-->
    <declare-styleable name="MyCircleImageView">
        <attr name="src" format="reference"/><!--引用类型-->
    </declare-styleable>
</resources>

在attr中填写属性包括属性名称和属性取值类型

在activity的xml文件中就可以调用这个自定义控件和它的属性了

<com.xbl.view.MyCircleImageView
        android:layout_width="200dp"
        android:layout_height="200dp"
        app:src="@drawable/co2"
        />

2.得到src属性
上面只是为View添加了这个属性,运行的话src背景是不会显示的,因为系统是不知道src是干什么的
下面就是如何得到这个属性值,并操作它

//方便在XML文件中使用
    public MyCircleImageView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        //得到所有属性的集合
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.MyCircleImageView);
        //得到src属性所附的值
        srcImage = ta.getResourceId(R.styleable.MyCircleImageView_src, R.mipmap.ic_launcher);
        //因为ta中有很多数据,所以回收数据
        ta.recycle();
    }

这样我们就可以得到 XML文件中填写的src中的图片资源了

而下面就是重头戏了,如何将这个背景以圆形的形式显示到自定义View上

将图片显示成圆形

显示成圆形是因为显示的图片是一个圆形的,而不是自定义View被切割成圆形
自定义的形状不会改变就是方形的
实现原理:

得到src背景这个Bitmap的宽高
根据这个宽高为View设置圆形视图层(Bitmap) desc层
并在desc层上添加画布
用画笔取圆形视图层和图片层重合的地方,进行绘制图片
返回desc层
用View的onDreaw方法绘制desc层

这里写图片描述
看似很麻烦,很难理解,用代码一步步实现吧~

1.得到图片的宽高(srcImage就是图片资源R.drawable.xxx)

 Bitmap srcBitmap=BitmapFactory.decodeResource(getResources(), srcImage);
            int w=srcBitmap.getWidth();
            int h=srcBitmap.getHeight();

2.根据图片的宽高在View上设置desc视图层

 //desc层,设置最终要的形状
            //根据原图的宽高创建一个bitmap图片 RGB.565最小的内存保存,ARGB_4444,8888更加清楚
             Bitmap descBitmap=Bitmap.createBitmap(w,h,Bitmap.Config.ARGB_4444);

3.在desc视图层上画圆形的画布

//绘制画布形状
        RectF rectF = new RectF(0, 0, w, h);
        //创建内切椭圆
        //得到最底层desc的画布
        Canvas descCanvas = new Canvas(descBitmap);
        Paint paint = new Paint();
        paint.setColor(Color.WHITE);
        //抗锯齿和防抖动
        paint.setAntiAlias(true);
        paint.setDither(true);
        descCanvas.drawOval(rectF, paint);

3.用画笔得到画布和图片视图所相交的部分,将相交的部分绘制在画布上

//设置显示取相交部分
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        //将内容绘制在画布上
        descCanvas.drawBitmap(srcBitmap, 0, 0, paint);

4.最后将这个已经绘制好的desc层返回

//获取圆形的图片
    private Bitmap getCircleImage() {
        //绘制的图片内容
        Bitmap srcBitmap = BitmapFactory.decodeResource(getResources(), srcImage);
        int w = srcBitmap.getWidth();
        int h = srcBitmap.getHeight();
        //desc层,设置最终要的形状
        //根据原图的宽高创建一个bitmap图片
        // RGB.565最小的内存保存,ARGB_4444,8888更加清楚
        Bitmap descBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_4444);
        //绘制画布形状
        RectF rectF = new RectF(0, 0, w, h);
        //创建内切椭圆
        //得到最底层desc的画布
        Canvas descCanvas = new Canvas(descBitmap);
        Paint paint = new Paint();
        paint.setColor(Color.WHITE);
        //抗锯齿和防抖动
        paint.setAntiAlias(true);
        paint.setDither(true);
        descCanvas.drawOval(rectF, paint);
        //设置显示取相交部分
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        //将内容绘制在形状上
        descCanvas.drawBitmap(srcBitmap, 0, 0, paint);
        return descBitmap;
    }

5.在onDreaw方法中绘制视图层

 @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawBitmap(getCircleImage(), 0, 0, null);
    }

这样就可以显示出圆形View的效果了

这里写图片描述

第一个是一个正常的ImageView显示,第二个是自定义View

但是细心的人可能会发现如果我为这个View设置的宽高都是wrap_content,这个图片是显示不出来的,这是因为系统不知道你的自适应的大小为多少,所以要重写测量方法,告诉系统你这个wrap_content的值是多少

@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //获取父亲的测量结果(widthMeasureSpec 是一个32位的int值,
        // 其中高2位为测量的模式,低30位为测量的大小,模式常用的为两种
        // EXACTLY 精确模式   宽高为一个精确值  xxdp或者match_parent
        //AT_MOST  最大值   宽高为wrap_content
        // )
        int wMode = MeasureSpec.getMode(widthMeasureSpec);
        int hMode = MeasureSpec.getMode(heightMeasureSpec);
        int width = MeasureSpec.getSize(widthMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);
        //实际图片宽高
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), srcImage);
        int w = bitmap.getWidth();
        int h = bitmap.getHeight();
        //如果是自适应,则手动为控件设置宽高
        if (wMode == MeasureSpec.AT_MOST) {
            width = w;
        }
        if (hMode == MeasureSpec.AT_MOST) {
            height = h;
        }
        //为控件设置宽高属性,宽高为图片的宽高
        setMeasuredDimension(width, height);
    }

最后附上所有代码

public class MyCircleImageView extends View {
    private int srcImage;

    //方便代码的初始化
    public MyCircleImageView(Context context) {
        super(context);
    }

    //方便在XML文件中使用
    public MyCircleImageView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        //得到所有属性的集合
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.MyCircleImageView);
        //得到src属性所附的值
        srcImage = ta.getResourceId(R.styleable.MyCircleImageView_src, R.mipmap.ic_launcher);
        //因为ta中有很多数据,所以回收数据
        ta.recycle();
    }

    //获取圆形的图片
    private Bitmap getCircleImage() {
        //绘制的图片内容
        Bitmap srcBitmap = BitmapFactory.decodeResource(getResources(), srcImage);
        int w = srcBitmap.getWidth();
        int h = srcBitmap.getHeight();
        //desc层,设置最终要的形状
        //根据原图的宽高创建一个bitmap图片
        // RGB.565最小的内存保存,ARGB_4444,8888更加清楚
        Bitmap descBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_4444);
        //绘制画布形状
        RectF rectF = new RectF(0, 0, w, h);
        //创建内切椭圆
        //得到最底层desc的画布
        Canvas descCanvas = new Canvas(descBitmap);
        Paint paint = new Paint();
        paint.setColor(Color.WHITE);
        //抗锯齿和防抖动
        paint.setAntiAlias(true);
        paint.setDither(true);
        descCanvas.drawOval(rectF, paint);
        //设置显示取相交部分
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        //将内容绘制在形状上
        descCanvas.drawBitmap(srcBitmap, 0, 0, paint);
        return descBitmap;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawBitmap(getCircleImage(), 0, 0, null);
    }
    //解决wramp_content不显示问题

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //获取父亲的测量结果(widthMeasureSpec 是一个32位的int值,
        // 其中高2位为测量的模式,低30位为测量的大小,模式常用的为两种
        // EXACTLY 精确模式   宽高为一个精确值  xxdp或者match_parent
        //AT_MOST  最大值   宽高为wrap_content
        // )
        int wMode = MeasureSpec.getMode(widthMeasureSpec);
        int hMode = MeasureSpec.getMode(heightMeasureSpec);
        int width = MeasureSpec.getSize(widthMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);
        //实际图片宽高
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), srcImage);
        int w = bitmap.getWidth();
        int h = bitmap.getHeight();
        //如果是自适应,则手动为控件设置宽高
        if (wMode == MeasureSpec.AT_MOST) {
            width = w;
        }
        if (hMode == MeasureSpec.AT_MOST) {
            height = h;
        }
        //为控件设置宽高属性,宽高为图片的宽高
        setMeasuredDimension(width, height);
    }
}

源码下载地址 ,源码里面还有我自定义的其他一些控件,这个圆形的控件是
MyCircleImageView
我知道没有人下载,但是还是要po上 酱酱~~

https://github.com/XuDaHaoRen/CutCirCleDemo

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值