Java 自定义视图。获取旋转视图中点在父视图上的位置

Java 自定义视图。获取旋转视图中点在父视图上的位置,java,android,android-custom-view,Java,Android,Android Custom View,场景是,我有一个在白色背景FrameLayout内具有自定义图形的视图。没有旋转,它只是一个平面圆。但是,正如我使用 看起来是这样的: 如果是平面圆视图,我可以很容易地获得带有一条视图线的黑色圆的位置,因为它与框架布局的大小相同。也就是说,如果它位于X(32),Y(100)上,它在框架布局上的位置是X(32),Y(100)。但是,如果视图旋转而框架布局未旋转,如何在框架布局上获得其正确的相对位置X和Y 我所能提供的只是视图上未旋转的点的XY位置。显然我错了,因为透视投影,仅计算旋转X并不容易。

场景是,我有一个在白色背景FrameLayout内具有自定义图形的视图。没有旋转,它只是一个平面圆。但是,正如我使用

看起来是这样的:

如果是平面圆视图,我可以很容易地获得带有一条视图线的黑色圆的位置,因为它与框架布局的大小相同。也就是说,如果它位于X(32),Y(100)上,它在框架布局上的位置是X(32),Y(100)。但是,如果视图旋转而框架布局未旋转,如何在框架布局上获得其正确的相对位置X和Y


我所能提供的只是视图上未旋转的点的XY位置。

显然我错了,因为透视投影,仅计算旋转X并不容易。所以,这就是你可以做到的,yStar在视图的顶部为1,在底部为-1,对于x坐标,你可以使用与触摸相同的方式,因为你在x轴上旋转,它不会改变

final float rotationDegrees = 45 ;
final double rotationRadians = Math.toRadians(rotationDegrees);
final double ninetyDegrees = Math.toRadians(90);
customView.setRotationX(rotationDegrees);

frameLayout.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if(event.getAction() == MotionEvent.ACTION_DOWN) {

            float cy = frameLayout.getHeight() / 2;

            float yt = (event.getY() - cy) / -cy;

            double ms = Math.tan(ninetyDegrees + rotationRadians);
            double targetX = (yt-ms) / ms;
            double targetY = (Math.pow(yt, 2) - yt*ms) / ms;

            double yStar = Math.sqrt(Math.pow(targetX- -1, 2) + Math.pow(targetY- 0, 2));

            if(targetY>0) yStar *= -1;

            Log.d("MainActivity", String.valueOf(yStar));

        }
        return true;
    }
});
说明:

假设右侧从(1;1)到(1;-1)的部分是从侧面查看的框架布局。左侧从(-1;1)到(-1;-1)的线是自定义视图,而不是旋转视图。 A是您接触框架布局的点。R是触摸的投影,它通过原点,这是焦点。S是旋转视图所在的直线。B是旋转视图上投影框架布局上的触摸的点。旋转视图上触摸的y坐标(yStar)是B和F之间的距离(F是自定义视图的中心)

一旦你有了所有线条的图片,这里是你如何计算yStar的:

yt=在-1和1之间缩放的触摸式框架布局的y坐标
A=(1;yt)
R=(x-1)/-1=(y-yt)/-yt->通过A和原点的线
R=y=-yt((x-1)/-1)+yt
R=y=-yt*(-x+1)+yt
R=y=yt*x
S=y=ms*x+ms->坡度ms通过F(-1;0)的直线
ms=tan(90+旋转角度)

B将是R和S之间的中间点。如果它们具有相同的坡度(ms=yt),则不会有交点。 所以

yt*x=ms*x+ms
yt*x-ms*x=ms
x*(yt-ms)=ms
x=(yt-ms)/ms->B的x坐标

y=yt*((yt-ms)/ms)
y=(yt^2-yt*ms)/ms->B的y坐标


现在计算距离F,如果y低于F,则乘以-1。

| | |免责声明:只是一个想法| |可能会运行上面显示的布局的一个不可见视图,但所有视图都没有任何角度和倾斜,并将您的坐标从中移除?然后,只需将上面的视图用作向用户显示的视图,但不会从中收集实际代码。唯一的代码,然后传输到隐藏的视图,然后你做你的计算了吗?我知道我可能已经得到了你的问题错误的另一次,但我觉得这一次我们更接近。如果你看我贴的图,你有B,你想找到A?@lelloman lemme花点时间理解它,我仍在研究它是的,我的答案现在是这样的,你点击框架布局,你就有了点击的坐标。然后它会给你自定义视图的等效坐标,就像它没有旋转一样。我理解你的答案,但事实并非如此。那里的圆形视图在X轴上旋转了50度,这意味着它就像一枚硬币被稍微翻转了一下。没有旋转,它只是一个平面圆,左边的线是一条直线。线坐标上的点很容易在framelayout上定位,因为它们完全相同。但是,如果视图在X轴上旋转50度,它在framelayout上的位置将完全不同。这就是我想要得到的。@Sheychan无论如何,我认为这个问题只对x更容易,我要吃点东西,然后更新答案
final float rotationDegrees = 45 ;
final double rotationRadians = Math.toRadians(rotationDegrees);
final double ninetyDegrees = Math.toRadians(90);
customView.setRotationX(rotationDegrees);

frameLayout.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if(event.getAction() == MotionEvent.ACTION_DOWN) {

            float cy = frameLayout.getHeight() / 2;

            float yt = (event.getY() - cy) / -cy;

            double ms = Math.tan(ninetyDegrees + rotationRadians);
            double targetX = (yt-ms) / ms;
            double targetY = (Math.pow(yt, 2) - yt*ms) / ms;

            double yStar = Math.sqrt(Math.pow(targetX- -1, 2) + Math.pow(targetY- 0, 2));

            if(targetY>0) yStar *= -1;

            Log.d("MainActivity", String.valueOf(yStar));

        }
        return true;
    }
});