自定义view之实现圆形图片imageview

感谢菜鸟教程提供的教程以及案例。本文根据是根据案例进行的自我实现。(弱引用什么的会影响新手理解)

8.3.6 Paint API之—— Xfermode与PorterDuff详解(三) | 菜鸟教程 (runoob.com)

实现方式:通过两个图层,图层A绘制图片,图层B绘制遮罩层,然后以相交模式将B放在A上,即可实现圆形图片。主要是针对

mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));的实际应用。

讲解:本文中使用到三个画布canvas,分别是整个视图的画布函数形参canvasA,图片画图canvasB,遮罩层canvasC。主要实现是先绘制B,再设置画笔格式为DST_IN,然后在B上绘制C,最后把B绘制到A上。

记录一下:mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));

关于两个图层的层叠方式,共有18种。

DST 是先绘制的图层A,SRC是后绘制的图B。使用DST_IN表示将A和B的相交部分绘制为A的图层,其余部分不显示。所以使用DST_IN要先绘制照片,后绘制遮罩。如果先绘制遮罩后绘制图片就需要使用SRC_IN。

代码实现:(记得在ondraw方法中去掉父类的构造方法,否则会重复绘制)

public class MyCircleView extends androidx.appcompat.widget.AppCompatImageView {

    Paint mPaint;

    public MyCircleView(Context context) {
        super(context);
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
    }

    public MyCircleView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
    }

    public MyCircleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
    }


    @Override
    public void setImageResource(int resId) {
        super.setImageResource(resId);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //取短边为范围
        int size=Math.min(getMeasuredHeight(),getMeasuredWidth());
        setMeasuredDimension(size,size);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        Drawable drawable = getDrawable();
        if (drawable == null) {
            return;
        }

        // 获取图片的宽高
        int width = drawable.getIntrinsicWidth();
        int height = drawable.getIntrinsicHeight();

        float scale=getWidth()*1.0f/Math.min(width,height);
        if (scale>1){
            drawable.setBounds(0, 0, (int) (scale * width), (int) (scale * height));
        }
        //先拿一块画布绘制图片,设置画笔模式,再拿一块画布绘制遮罩
        Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
        Canvas drawCanvas = new Canvas(bitmap);
        drawable.draw(drawCanvas);

        Bitmap bitmap2 = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas1 = new Canvas(bitmap2);
        Paint paint = new Paint();
        canvas1.drawCircle(getWidth() / 2, getWidth() / 2, getWidth() / 2, paint);
        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
        drawCanvas.drawBitmap(bitmap2,0,0,mPaint);
        canvas.drawBitmap(bitmap,0,0,null);
        mPaint.setXfermode(null);
    }
}

除此之外,你可以在res/attr.xml文件下给自定义的view设置xml输入属性。然后在构造函数中获取这些属性并操作。

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="MyCircleView ">    <!-- 你自定义的view名称 -->
        <attr name="Radius" format="dimension"/>
        <attr name="type">
            <enum name="circle" value="0"/>
            <enum name="round" value="1"/>
        </attr>
    </declare-styleable>
</resources>
//在构造函数中,通过上下文context获取
public CircleImageView(Context context, AttributeSet attrs) {
    TypedArray tArray = context.obtainStyledAttributes(attrs, R.styleable.CircleImageView);
    int mBorderRadius = tArray.getDimensionPixelSize(R.styleable.CircleImageView_Radius, BODER_RADIUS_DEFAULT);
    int type = tArray.getInt(R.styleable.CircleImageView_type, TYPE_CIRCLE);
    tArray.recycle();//释放资源,建议是把属性赋值给全局变量后,就释放掉这个资源。
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值