【问题标题】:Drawing a line following finger - motionevent.getX() and getY() incorrect UPDATE在手指后面画一条线 - motionevent.getX() 和 getY() 不正确更新
【发布时间】:2013-11-08 16:37:22
【问题描述】:

更新:请再次阅读整个问题 :-)

背景:

我通过创建自定义视图然后将这些视图添加到TableLayout 来创建点网格。目的是让我能够以某种方式从这些点中的一个点到另一个点画一条线,以便当按下一个点时,一条线从按下的点的中心开始到手指当前所在的点接触。当手指被拖过另一个点时,线条会在该点的中心结束。结果是从按下的点的中心到手指拖过的点的中心绘制一条线。

为了在TableLayout 上创建一条线,我创建了一个新的自定义视图,它使用canvas.drawLine() 方法在点之间创建了一条线。然后我创建了一个FrameLayout,在其中放置了TableLayout 和LineView。这意味着线视图将能够绘制在 TableLayout 的顶部。

现状:

我在 DotView 类中添加了触摸监听器,以便它可以拥有自己的“触摸反馈”。活动中还有另一个触摸侦听器,我试图用它来获取绘制线所需的点。据我所知,触摸监听器工作正常 - 它们不会相互干扰。

问题是获取正确的坐标来绘制线条。我尝试了多种方法来获取按下的点的中心坐标(线的起点),但我仍然没有管理它。这个问题,有更多信息:Get the coordinates of the center of a view。第二部分是获取线的正确端点。出于这个问题的目的,我只想让行尾跟随手指的位置。我认为这和motionevent.getX() / getY() 一样简单,但这并没有奏效。相反,发生的事情是相对于点布局的比例坐标和相对于整个布局/屏幕的坐标之间存在混淆。

简单地说:getX() 和 getY() 值不正确,这就是我要解决的问题。

如截图所示,当我按下一个点时,线的起点大致在正确的位置,但终点却很远。我真的无法解释为什么。

我尝试了getRawX()getRawY(),它们返回的值更加准确,但填充量仍然不正确(或类似的东西 - 我不是 100% 理解)。

这显示了我的代码

在我的Activity

    LineView test;
    FrameLayout fl;
     float startPointX = 0;
    float startPointY = 0;

    // Removed 

    @Override
    public boolean onTouch(View view, MotionEvent event) {

        float eventX = event.getX();
        float eventY = event.getY();

        int[] loc = new int[2];

        switch (event.getAction()) {

        case MotionEvent.ACTION_DOWN:

            if (view instanceof DotView) {

                DotView touchedDv = (DotView) view;

                int dotColor = touchedDv.getColor();
                test.setColor(dotColor);

                float[] f = touchedDv.getDotCenterLocationOnScreen();
                startPointX = f[0];
                startPointY = f[1];

                test.setPoints(startPointX, startPointY, eventX, eventY);
fl.addView(test);
            }

            vib.vibrate(35);


            return false; 
        case MotionEvent.ACTION_MOVE:

            test.setPoints(startPointX, startPointY, eventX, eventY);

            break;
        case MotionEvent.ACTION_UP:

            fl.removeView(test);

            return false;

        default:
            return false;
        }

        return true;
    }

最后是LineView

public class LineView extends View {

public static final int LINE_WIDTH = 10;
Paint paint = new Paint();

float startingX, startingY, endingX, endingY;

public LineView(Context context) {
    super(context);

    paint.setColor(Color.MAGENTA);
    paint.setStrokeWidth(LINE_WIDTH);

}

public void setPoints(float startX, float startY, float endX, float endY) {

    startingX = startX;
    startingY = startY;
    endingX = endX;
    endingY = endY;
            invalidate();
}


@Override
public void onDraw(Canvas canvas) {

    canvas.drawLine(startingX, startingY, endingX, endingY, paint);

}

注意事项:

  • 我正在调用左上角的点"dot 1"

  • 屏幕截图可能不完全准确,因为我的手指在移动 当我截屏时稍微有点,但我描述的行为是 正在发生。

如果需要任何其他信息/代码,我很乐意提供。

感谢您抽出宝贵时间阅读本文 - 抱歉,写了这么久!

【问题讨论】:

  • 你解决了吗?如果不尝试更好地解释你在做什么。并且将触摸侦听器设置在层次结构中更高的视图而不是点视图上可能会更有意义,尤其是当您在其边界之外绘制时(从我在图像中看到的)。
  • @Luksprog 不,我还没有解决这个问题 - 我将编辑主要问题以尝试使其更清晰。我已将每个点视图注册到触摸侦听器,因此我可以首先检测在ACTION_DOWN 上按下了哪个点,然后检测手指已在ACTION_MOVE 上拖过哪个点视图
  • @Luksprog 我主要更新了这个问题。我希望它现在更有意义。

标签: android android-canvas android-view touch-event motionevent


【解决方案1】:

我在 DotView 类中添加了触摸监听器,这样它就可以拥有 它自己的“触摸反馈”。中还有另一个触摸监听器 我试图用来获得绘制所需积分的活动 线。据我所知,触摸监听器工作正常 - 他们 互不干扰。

我不太明白为什么你需要两个触摸监听器。要画线,TableLayout 上的触摸监听器应该绰绰有余。

您的代码的问题(或至少从我所见)是您使用getLocationOnScreen(coordsArray) 方法而没有将返回的值转换回LineView 的坐标系。例如,您获得DotView 的坐标,即 x 和 y。然后在LineView 中使用此值。但是,LineView 在进行绘图时将使用其自己的(标准)坐标系,该坐标系将视图的左上角置于 (0,0) 并且坐标将不匹配。这是一个示例:假设您触摸第一个高度为 50 的DotViewgetLocationOnScreen() 方法返回的 y 为 100。您计算出DotView 的中心,它将位于 125(100 + 50 / 2)。在LineView 中使用此值将偏离正常位置,因为实际绘图将在 125 处完成,在屏幕坐标中将在视觉上转换为 225 的 y(getLocationOnScreen() + 125 返回的 100)。

无论如何,我已经使用getLocationOnScreen() 方法做了一个小例子来做你想做的事情(你可以找到here)。

【讨论】:

  • 哇!!非常感谢 Luksprog 的精彩解释和示例代码。现在更有意义了:-)。
  • 我评论了一个问题,但我修复了它。 :-)
  • 嗨@Luksprog - 我不知道你是否知道:我想将我的应用程序发布到包含你的示例代码的 Play 商店。我稍微修改了它,并在活动中添加了更多我自己的代码。据我所知,我需要做的就是在我的应用程序中的某个地方显示许可证。这是正确的吗?
  • @RiThBo 该代码是在 Apache 许可证下发布的,据我所知,是的,只需要在应用程序中显示 Apache 许可证(当然我不是律师)。从我的角度来看,我发布了代码来提供帮助,您可以以任何您想要的方式使用代码。
  • @andre3wap 向 DotView 类添加一个布尔字段,表示类似 wasMatched 的状态(最初为 false)。在 DotView 类的 onDraw() 方法中,使用 wasMatched 字段不绘制任何内容(如果 wasMatched 为真)或绘制当前内容(当前代码,当 wasMatched 为假时)。然后,当您匹配两个 DotView(开始和当前)时,将它们的 wasMatched 字段更新为 true。您确实需要向触摸侦听器添加一些逻辑,以忽略已将 wasMatched 设置为 true 的 DotViews 中的触摸。
猜你喜欢
  • 1970-01-01
  • 2011-04-08
  • 2011-05-17
  • 2011-09-08
  • 1970-01-01
  • 2018-06-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多