如何在变换矩阵后获取视图的适当边界

13

我有一个自定义视图,其中使用了变换。到目前为止,像 setRotationY()setScaleX()setTranslationY() 或甚至 getMatrix() 这样的函数都按预期工作,我能够操纵我的视图并且它正常显示。

然而,在某些情况下会遇到一些问题。例如,像 getHitRect() 这样的函数返回完全奇怪的值!这不利于我的触摸事件。

我尝试了重载函数,但特别是在使用旋转或缩放(平移可以正常工作)时仍然存在问题。我认为这与矩阵是以子坐标表示有关,那么如何将其转换为父坐标系呢?

@Override
    public void getHitRect(Rect outRect){

        RectF rect = new RectF(); 
        rect.top = (float) this.getTop(); 
        rect.bottom = (float) this.getBottom(); 
        rect.left = (float) this.getLeft(); 
        rect.right = (float) this.getRight();      

    this.getMatrix().mapRect(rect);
        rect.round(outRect);
    }

我可以直接从某个函数中获取一些更直接的值吗?例如新的高度、宽度、顶部或底部。

1个回答

10
当覆盖ViewGroup的“getChildStaticTransformation”方法或使用变换函数如setRotationY()setScaleX()setTranslationY()getMatrix()(从API 11可用)时,只会影响渲染矩阵,因此您自定义的子视图将返回远离子视图绘制位置的边界“Rects”。大多数情况下,这不是问题,但当您开始点击时,问题就出现了。以下是我解决该问题的方法。我相信可能有更好的方法,但由于在这个主题上我没找到太多东西,所以这里是我的方法。
在ViewGroup中进行重载:
public interface Itransformable {
    public void setTransformationMatrix(Matrix trsMatrix);
}

@Override
protected boolean getChildStaticTransformation(View child, Transformation t) {
    if (child instanceof Itransformable){   
        t.clear();
        t.setTransformationType(Transformation.TYPE_MATRIX);
        ...
        // Do whatever transformation you want here
        ...
        ((Itransformable)child).setTransformationMatrix(t.getMatrix());
        return true;
    } else {
        return false;
    }
}

这是自定义视图的子视图: 请注意,我没有直接在自定义视图中存储变换矩阵,而是存储了变换后的矩形。如果您想要存储矩阵(例如以后进行点之类的转换),则可能需要克隆它,因为矩阵会以某种奇怪的方式被更改,例如回收等。

public class MyCustomView extends View implements MyViewGroup.Itransformable{

private Rect mViewRect = null;

public void setTransformationMatrix(Matrix trsMatrix){
    if (trsMatrix!=null){
        RectF rect = new RectF();
        rect.top = 0;
        rect.bottom = (float) this.getHeight(); 
        rect.left = 0; 
        rect.right = (float) this.getWidth();  

        trsMatrix.mapRect(rect);
        rect.offset((float) this.getLeft(), (float) this.getTop());

        if (mViewRect == null) mViewRect = new Rect();
        rect.round(mViewRect);
    }
}

public Rect getTransformatedRect() {
    if (mViewRect!=null){
        // OutOfScreen WorkArround - As the view is not Displayed, mViewRect doesn't get updated.
        if(getRight() < 0 || getLeft() > mParentWidth){
            return new Rect(getLeft(),getTop(),getRight(),getBottom());
        } else {
            return mViewRect;
        }
    } else {
        return new Rect(getLeft(),getTop(),getRight(),getBottom());
    }
}

@Override
public void getHitRect(Rect outRect){

    if (mViewRect == null){
        super.getHitRect(outRect);
    } else {
        outRect.set(getTransformatedRect());
    }
}

针对 Android >= 4.0 的另一件事情是:如果您在单击视图时,getHitRect() 不会自动调用。为了增加对使用 SDK < 4.0 的项目的兼容性,即使不完美,也可以在父级上使用 isTransformedTouchPointInView() - olivier_sdg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接