Android自定义View学习之圆角图片(圆形图片)

圆形图片的实现方式有很多种,首先我分享下自己所知道的一种实现方式,这种方式的实现对角度的控制很灵活,可以在xml中自由的设置,实现的过程中使用到了PorterDuffXfermode这个类,网络上对PorterDuffXfermode的解释:

类android.graphics.PorterDuffXfermode继承自android.graphics.Xfermode。在用Android中的Canvas进行绘图时,可以通过使用PorterDuffXfermode将所绘制的图形的像素与Canvas中对应位置的像素按照一定规则进行混合,形成新的像素值,从而更新Canvas中最终的像素颜色值,这样会创建很多有趣的效果。当使用PorterDuffXfermode时,需要将其作为参数传给Paint.setXfermode(Xfermode xfermode)方法,这样在用该画笔paint进行绘图时,Android就会使用传入的PorterDuffXfermode,如果不想再使用Xfermode,那么可以执行Paint.setXfermode(null)。

我的理解是canva在绘制俩个图像有重叠时,会以什么样的形式显示出来,只需要取决于你给它传入的什么模式就行了(其中总共16种模式,十六种模式图像网络上也有);PorterDuffXfermode功能挺强大的,想了解可以百度

效果图:

Android自定义View学习之圆角图片(圆形图片)_第1张图片

一、该自定义View同样继承ImageView,重写onDraw方法

 @Override
    protected void onDraw(Canvas canvas) {
        //创建同等大小的位图
        Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_4444);
        //创建带有位图的画布
        mCanvas=new Canvas(bitmap);
        super.onDraw(mCanvas);
        //绘制矩形内接圆(椭圆)外部分,简单就是去掉的四个角所组成的图形
        drawGraphical();
        canvas.drawBitmap(bitmap,0,0,mPaintBitmap);
    }
代码中创建了一个带有位图的画布,以参数的形式,通过super.onDraw(mCanvas)传给父类,我的理解是相当于两个画布mCanvas和canvas重叠在一起,mCanvas在上面,各自在自己上面绘制图形,上面的PorterDuffXfermode就使用在mCanvas上,来约束mCanvas绘制显示的区域


private void drawGraphical() {
        //限制mRadius值的规范性
        checkRadius();
        //左上
        mPath.moveTo(0, mRadius);
        mPath.lineTo(0, 0);
        mPath.lineTo(mRadius, 0);
        //圆弧路径
        mPath.arcTo(new RectF(0, 0, mRadius * 2, mRadius * 2), 270, -90);

        //左下
        mPath.moveTo(0, getHeight() - mRadius);
        mPath.lineTo(0, getHeight());
        mPath.lineTo(mRadius, getHeight());
        mPath.arcTo(new RectF(0, getHeight() - mRadius * 2, mRadius * 2, getHeight()), 90, 90);

        //右下
        mPath.moveTo(getWidth() - mRadius, getHeight());
        mPath.lineTo(getWidth(), getHeight());
        mPath.lineTo(getWidth(), getHeight() - mRadius);
        mPath.arcTo(new RectF(getWidth() - mRadius * 2, getHeight() - mRadius * 2, getWidth(), getHeight()), 0, 90);

        //右上
        mPath.moveTo(getWidth(), mRadius);
        mPath.lineTo(getWidth(), 0);
        mPath.lineTo(getWidth() - mRadius, 0);
        mPath.arcTo(new RectF(getWidth() - mRadius * 2, 0, getWidth(),mRadius * 2), 270, 90);
        mCanvas.drawPath(mPath, mPaintPath);
    }
绘制需要遮挡的图形区域,moveTo(x,y)从哪个点开始,lineTo(x,y)到哪个点,arcTo(new RectF())绘制圆弧路径,drawPath()根据规定的路径开始绘制,绘制完,大概的样子就是一个矩形去掉内接圆(长和宽相等)剩下的部分就是的了,自己不会画图,自己想象下吧


private void init(Context context, AttributeSet attrs) {
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CornerImageView);
        mRadius = typedArray.getDimension(R.styleable.CornerImageView_cornerRadius, -1);
        mPaintBitmap=new Paint();
        mPaintBitmap.setAntiAlias(true);
        mPaintPath=new Paint();
        mPaintPath.setAntiAlias(true);
        mPorterDuffXfermode=new PorterDuffXfermode(PorterDuff.Mode.DST_OUT);
        mPaintPath.setXfermode(mPorterDuffXfermode);
        //图形对象
        mPath=new Path();
    }
初始化代码,
PorterDuff.Mode.DST_OUT
取底部相交图形之外的部分


二、全部代码

package com.yufs.myimageview.view;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.widget.ImageView;

import com.yufs.myimageview.R;

/**
 * Created by yufs on 2017/5/22.
 */

public class CornerImageView extends ImageView{
    private Canvas mCanvas;
    private Paint mPaintBitmap;//绘制bitmap的画笔
    private Paint mPaintPath;//绘制path的画笔
    private Path mPath;//path对象
    private float mRadius=0;//圆角弧度
    private PorterDuffXfermode mPorterDuffXfermode;//
    public CornerImageView(Context context) {
        super(context);
        init(context, null);
    }

    public CornerImageView(Context context, AttributeSet attrs) {
        this(context,attrs,0);
    }

    public CornerImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context,attrs);
    }

    private void init(Context context, AttributeSet attrs) {
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CornerImageView);
        mRadius = typedArray.getDimension(R.styleable.CornerImageView_cornerRadius, -1);
        mPaintBitmap=new Paint();
        mPaintBitmap.setAntiAlias(true);
        mPaintPath=new Paint();
        mPaintPath.setAntiAlias(true);
        mPorterDuffXfermode=new PorterDuffXfermode(PorterDuff.Mode.DST_OUT);
        mPaintPath.setXfermode(mPorterDuffXfermode);
        //图形对象
        mPath=new Path();
    }



    @Override
    protected void onDraw(Canvas canvas) {
        //创建同等大小的位图
        Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_4444);
        //创建带有位图的画布
        mCanvas=new Canvas(bitmap);
        super.onDraw(mCanvas);
        //绘制矩形内接圆(椭圆)外部分,简单就是去掉的四个角所组成的图形
        drawGraphical();
        canvas.drawBitmap(bitmap,0,0,mPaintBitmap);
    }

    private void drawGraphical() {
        //限制mRadius值的规范性
        checkRadius();
        //左上
        mPath.moveTo(0, mRadius);
        mPath.lineTo(0, 0);
        mPath.lineTo(mRadius, 0);
        //圆弧路径
        mPath.arcTo(new RectF(0, 0, mRadius * 2, mRadius * 2), 270, -90);

        //左下
        mPath.moveTo(0, getHeight() - mRadius);
        mPath.lineTo(0, getHeight());
        mPath.lineTo(mRadius, getHeight());
        mPath.arcTo(new RectF(0, getHeight() - mRadius * 2, mRadius * 2, getHeight()), 90, 90);

        //右下
        mPath.moveTo(getWidth() - mRadius, getHeight());
        mPath.lineTo(getWidth(), getHeight());
        mPath.lineTo(getWidth(), getHeight() - mRadius);
        mPath.arcTo(new RectF(getWidth() - mRadius * 2, getHeight() - mRadius * 2, getWidth(), getHeight()), 0, 90);

        //右上
        mPath.moveTo(getWidth(), mRadius);
        mPath.lineTo(getWidth(), 0);
        mPath.lineTo(getWidth() - mRadius, 0);
        mPath.arcTo(new RectF(getWidth() - mRadius * 2, 0, getWidth(),mRadius * 2), 270, 90);
        mCanvas.drawPath(mPath, mPaintPath);
    }

    /**
     * 如果未设置cornerRadius属性,或者设置的非法,默认是圆形
     */
    private void checkRadius() {
        float minValues;
        if(getWidth()>getHeight()){
            minValues=getHeight();
        }else{
            minValues=getWidth();
        }
        if(mRadius>minValues/2||mRadius<0){
            mRadius=minValues/2;
        }
    }
}

attrs文件



    
        
    


xml中使用



    
        

            

            


            

            
        
    





使用自定义属性时别忘记在顶部加入声明

xmlns:mimage="http://schemas.android.com/apk/res-auto"
mimage名字随意

green是一张图片,你可以用自己的演示看看,有什么问题,或者我说的有哪不对的,希望大神帮忙指点下,谢谢



你可能感兴趣的:(Android自定义控件)