Android视图“挖孔”研究

本文来看看如何在视图上挖一个孔,让视图层下层的视图可以展示出来。

核心方法

  • clipRect(@NonNull RectF rect, @NonNull Region.Op op)
  • clipRect(@NonNull Rect rect, @NonNull Region.Op op)
  • clipRect(@NonNull Rect rect)
  • clipOutRect(@NonNull Rect rect)
  • clipPath(@NonNull Path path, @NonNull Region.Op op)
  • clipPath(@NonNull Path path)
  • clipOutPath(@NonNull Path path)

参数类型Region.Op为枚举类型,直接影响裁剪区域。

public enum Op {
        DIFFERENCE(0),
        INTERSECT(1),
        UNION(2),
        XOR(3),
        REVERSE_DIFFERENCE(4),
        REPLACE(5);

        Op(int nativeInt) {
            this.nativeInt = nativeInt;
        }
        
        @UnsupportedAppUsage
        public final int nativeInt;
    }

从API级别**{@value Build.VERSION_CODES#P}开始,只有{@link Region.Op#INTERSECT}**和
{@link Region.Op#DIFFERENCE}是有效的,传入其他参数会抛异常IllegalArgumentException
如果想测试其他参数,请将build.gradle文件中的targetSdkVersion改为28以下。

各参数区别如下:

  • DIFFERENCE:差集(A - A∩B),前面裁剪区域相对于后面裁剪区域的差集,也就是前面的裁剪区域去掉前面的裁剪区域和后面的裁剪区域相交的区域以后,前面裁剪区域剩下的部分
  • INTERSECT:交集(A∩B),也就是前面的裁剪区域和后面的裁剪区域相交的区域
  • UNION:并集(A∪B),也就是前面的裁剪区域和后面的裁剪区域合并以后的区域
  • XOR:对称差集(A∪B - A∩B),前面裁剪区域和后面裁剪区域合并起来的区域去掉相交的区域所得到的区域
  • REVERSE_DIFFERENCE:差集(B - A∩B),后面裁剪区域相对于前面裁剪区域的差集,后面的裁剪区域去掉前面的裁剪区域和后面的裁剪区域相交的区域以后,后面的裁剪区域剩下的部分
  • REPLACE:直接使用后面的裁剪区域

示例

以下示例展示了视频或者图片裁剪区域选择的控件简单的移动功能。

public class DigHoleView extends View {

    private static final int SIZE = 400;

    private float mTouchX, mTouchY;

    private RectF mHoleRegion = new RectF();

    public DigHoleView(Context context) {
        this(context, null);
    }

    public DigHoleView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

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

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        mHoleRegion.set((getMeasuredWidth() - SIZE) / 2.0f, (getMeasuredHeight() - SIZE) / 2.0f, (getMeasuredWidth() + SIZE) / 2.0f, (getMeasuredHeight() + SIZE) / 2.0f);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.save();
        //  canvas.clipRect(0, 0, getWidth(), getHeight());
        canvas.clipRect(mHoleRegion, Region.Op.DIFFERENCE);
        canvas.drawColor(Color.argb(190, 0, 0, 0));
        canvas.restore();
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (MotionEvent.ACTION_DOWN == event.getAction()) {
            mTouchX = event.getX();
            mTouchY = event.getY();
            return mHoleRegion.contains(mTouchX, mTouchY);
        } else if (MotionEvent.ACTION_MOVE == event.getAction()) {
            float dx = event.getX() - mTouchX;
            float dy = event.getY() - mTouchY;
            mTouchX = event.getX();
            mTouchY = event.getY();
            mHoleRegion.offset(dx, dy);
            invalidate();
        }
        return super.onTouchEvent(event);
    }
}

感谢大家的支持,如有错误请指正,如需转载请标明原文出处!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值