android 自定义蒙层镂空

自定义蒙层挖空效果

在项目中,我们经常会遇到加盖蒙层的效果。当然,如果懒得话解决方法很简单,直接和UI要一张图片就搞定了。但图片比较占内存。如果内存比较紧张,这个时候,就考虑自己用代码实现了。

package com.jdjr.jdcn.demo.ext.widget;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.FrameLayout;

import com.jdjr.jdcn.demo.ext.R;

/**
 * Created by qishuaishuai on 2017/12/4.
 */

public class FrameLayoutWithHole extends FrameLayout {
    private Bitmap mEraserBitmap;
    private Canvas mEraserCanvas;
    private Paint mEraser;
    private float mDensity;
    private Context mContext;

    private float mRadius;
    private int mBackgroundColor;
    private float mRx;//默认在中心位置
    private float mRy;
    public FrameLayoutWithHole(@NonNull Context context) {
        super(context);
        mContext = context;
    }

    public FrameLayoutWithHole(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        mContext = context;

        TypedArray ta = context.obtainStyledAttributes(attrs,R.styleable.FrameLayoutWithHole);
        mBackgroundColor = ta.getColor(R.styleable.FrameLayoutWithHole_background_color,-1);
        mRadius =  ta.getFloat(R.styleable.FrameLayoutWithHole_hole_radius,0);
        mRx =  ta.getFloat(R.styleable.FrameLayoutWithHole_radius_x,0);
        mRy = ta.getFloat(R.styleable.FrameLayoutWithHole_radius_y,0);
        init(null,0);
        ta.recycle();
    }

    public FrameLayoutWithHole(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public FrameLayoutWithHole(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }
    public FrameLayoutWithHole(Context context, int backgroundColor,int radius
            ,int rx,int ry){//半径位置
        this(context);

        mBackgroundColor = backgroundColor;
        this.mRadius = radius;
        this.mRx = rx;
        this.mRy = ry;
        init(null,0);
    }
    private void init(AttributeSet attrs, int defStyle) {
        setWillNotDraw(false);
        mDensity = mContext.getResources().getDisplayMetrics().density;

        Point size = new Point();
        size.x = mContext.getResources().getDisplayMetrics().widthPixels;
        size.y = mContext.getResources().getDisplayMetrics().heightPixels;

        mRx = mRx*mDensity;
        mRy = mRy*mDensity;

        mRx = mRx !=0 ? mRx: size.x/2;
        mRy = mRy !=0 ? mRy: size.y/2;

        mRadius = mRadius !=0 ?mRadius:150;

        mRadius = mRadius*mDensity;

        mBackgroundColor  = mBackgroundColor !=-1?mBackgroundColor:Color.parseColor("#55000000");

        mEraserBitmap = Bitmap.createBitmap(size.x, size.y, Bitmap.Config.ARGB_8888);
        mEraserCanvas = new Canvas(mEraserBitmap);


        mEraser = new Paint();
        mEraser.setColor(0xFFFFFFFF);
        mEraser.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
        mEraser.setFlags(Paint.ANTI_ALIAS_FLAG);

        Log.d("tourguide", "getHeight: " + size.y);
        Log.d("tourguide", "getWidth: " + size.x);

    }
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mEraserBitmap.eraseColor(Color.TRANSPARENT);
            mEraserCanvas.drawColor(mBackgroundColor);

                mEraserCanvas.drawCircle(
                        mRx,
                        mRy,
                        mRadius, mEraser);

        canvas.drawBitmap(mEraserBitmap, 0, 0, null);

    }
}

先把整个代码贴出来,再逐一讲解如何使用。
这段代码改字tourguide, 因为不需要其他过多的功能,所以就把其他东西给删除了,只留了一个带有蒙层,中间镂空的布局。


  • 新建一个布局文件FrameLayoutWithHole, 将上述代码复制进去。
  • 上述的代码提供了两种实现方式,一是直接用java代码实现,可以直接new 一个布局文件,这样有个缺点就是布局不方便,想在蒙层上边添加一些提示之类的就比较麻烦了。所以我采用的是将其作为布局放入布局文件中,再xml中操作
  • 想将其作为布局,其实也很简单。 在value中间夹中找到attr.xml, 如果没有,就新建一个。然后将下边这段代码放进去。
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="FrameLayoutWithHole">
        <attr name="hole_radius" format="integer"/>
        <attr name="background_color" format="color"/>
        <attr name="radius_x" format="integer"/>
        <attr name="radius_y" format="integer"/>
    </declare-styleable>
</resources>

在布局文件里边就可以直接使用了。
hole_radius 为镂空圆的半径
background_color 为透明色背景
radius_x 为圆心的x 轴半径
radius_y 为圆心的y轴半径
这里写图片描述
大致效果图如图所示,

PS:因为没带手机,所以借用了UI图。其余在蒙层效果上添加了图片,动画,最后便可成为如图所示的下效果。

猜你喜欢

转载自blog.csdn.net/u013634213/article/details/78834195