美文网首页
android 布局实现子View不规则区域点击

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

作者: 黎院根 | 来源:发表于2022-09-07 16:02 被阅读0次

    在学习不规则区域点击中看到了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);
            }
        }
    
    }
    

    相关文章

      网友评论

          本文标题:android 布局实现子View不规则区域点击

          本文链接:https://www.haomeiwen.com/subject/ujfclltx.html