android 布局实现子View不规则区域点击

在学习不规则区域点击中看到了Android中不规则形状View的布局实现
以下是自己的学习总结:

我们知道android中View的不规则区域点击可以通过Path和Region实现,而在布局中依然可以用此方法实现,下面就是实现步骤:

1.android布局中都有drawChild方法,这是绘制每个子View的方法,而canvas可以通过clipPath来裁切不规则区域,我们通过拦截这个方法做操作:

@Override
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
    beforeChild(canvas,child,drawingTime);
    return super.drawChild(canvas, child, drawingTime);
}

Path path = new Path();
RectF bounds = new RectF();

private void beforeChild(Canvas canvas, View child, long drawingTime) {
    path.addRoundRect(new RectF(child.getLeft(),
                    child.getTop(),
                    child.getRight(),
                    child.getBottom()),
            80,
            80,
            Path.Direction.CW);
    path.computeBounds(bounds, true);
    canvas.clipPath(path);
}

2.android中dispatchTouchEvent()里的isTransformedTouchPointInView()虽然是hide但是protected方法,可以通过重写这个方法来实现View的点击区域判断:

public boolean isTransformedTouchPointInView(float x, float y, View child, PointF outLocalPoint) {
    final float[] point = getTempPoint();
    point[0] = x;
    point[1] = y;
    transformPointToViewLocal(point, child);
    boolean isInView = pointInView(child, point[0], point[1]);
    if (isInView && outLocalPoint != null) {
        outLocalPoint.set(point[0], point[1]);
    }
    return isInView;
}

getTempPoint()复制出来

private float[] mTempPoint;

    private float[] getTempPoint() {
        if (mTempPoint == null) {
            mTempPoint = new float[2];
        }
        return mTempPoint;
    }

child.pointInView这个方法不是public,我们需要去把View中的pointInView()复制出来

public boolean pointInView(View child, float localX, float localY) {
    return localX >= 0 && localY >= 0 && localX < (child.getRight() - child.getLeft()) &&
            localY < (child.getBottom() - child.getTop());
}

transformPointToViewLocal()是hide,同样复制出来

public void transformPointToViewLocal(float[] point, View child) {
    point[0] += getScrollX() - child.getLeft();
    point[1] += getScrollY() - child.getTop();
    //child.hasIdentityMatrix()和child.getInverseMatrix()用下面方法替换
    Matrix matrix = child.getMatrix();
    Matrix inverse = new Matrix();
    if (!matrix.isIdentity()) {
        matrix.invert(inverse);
        inverse.mapPoints(point);
    }
}

最后我们还需要判断是否在不规则的点击区域内

public boolean isTransformedTouchPointInView(float x, float y, View child, PointF outLocalPoint) {
    final float[] point = getTempPoint();
    point[0] = x;
    point[1] = y;
    transformPointToViewLocal(point, child);
    boolean isInView = pointInView(child, point[0], point[1]);
    if (isInView && outLocalPoint != null) {
        outLocalPoint.set(point[0], point[1]);
    }
    if (isInView) {
       //在这里判断是否在规则区域内
        Region region = new Region();
        region.setPath(path, new Region(
                (int) bounds.left,
                (int) bounds.top,
                (int) bounds.right,
                (int) bounds.bottom));
        if (!region.contains((int) x, (int) y)) {
            isInView = false;
        }
    }

    return isInView;
}

完整代码:

public class ClipFrameLayout extends FrameLayout {
    public ClipFrameLayout(@NonNull Context context) {
        super(context);
    }

    public ClipFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
        beforeChild(canvas, child, drawingTime);
        return super.drawChild(canvas, child, drawingTime);
    }

    Path path = new Path();
    RectF bounds = new RectF();

    private void beforeChild(Canvas canvas, View child, long drawingTime) {
        path.addRoundRect(new RectF(child.getLeft(),
                        child.getTop(),
                        child.getRight(),
                        child.getBottom()),
                80,
                80,
                Path.Direction.CW);
        path.computeBounds(bounds, true);
        canvas.clipPath(path);
    }

    private float[] mTempPoint;

    private float[] getTempPoint() {
        if (mTempPoint == null) {
            mTempPoint = new float[2];
        }
        return mTempPoint;
    }

    public boolean isTransformedTouchPointInView(float x, float y, View child, PointF outLocalPoint) {
        final float[] point = getTempPoint();
        point[0] = x;
        point[1] = y;
        transformPointToViewLocal(point, child);
        boolean isInView = pointInView(child, point[0], point[1]);
        if (isInView && outLocalPoint != null) {
            outLocalPoint.set(point[0], point[1]);
        }
        if (isInView) {
            Region region = new Region();
            region.setPath(path, new Region(
                    (int) bounds.left,
                    (int) bounds.top,
                    (int) bounds.right,
                    (int) bounds.bottom));
            if (!region.contains((int) x, (int) y)) {
                isInView = false;
            }

        }

        return isInView;
    }

    public boolean pointInView(View child, float localX, float localY) {
        return localX >= 0 && localY >= 0 && localX < (child.getRight() - child.getLeft()) &&
                localY < (child.getBottom() - child.getTop());
    }

    public void transformPointToViewLocal(float[] point, View child) {
        point[0] += getScrollX() - child.getLeft();
        point[1] += getScrollY() - child.getTop();

        Matrix matrix = child.getMatrix();
        Matrix inverse = new Matrix();
        if (!matrix.isIdentity()) {
            matrix.invert(inverse);
            inverse.mapPoints(point);
        }
    }

}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,142评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,298评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,068评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,081评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,099评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,071评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,990评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,832评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,274评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,488评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,649评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,378评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,979评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,625评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,643评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,545评论 2 352

推荐阅读更多精彩内容