检测SurfaceView上绘制的视图上的触摸

时间:2013-06-10 23:10:41

标签: java android graphics surfaceview

我正在开发游戏并遇到一些麻烦,我可能不会这样做,因为我是Android的图形方面的新手。

我有一个SurfaceViewArrayList我自己的Card对象扩展View。我覆盖onDraw对象的Card方法,然后在SurfaceView's onDraw中绘制所有内容。绘图部分可以正常工作。

我现在尝试使用onTouchListener检测单个卡的触摸时间,我为每张卡设置了侦听器,但它检测到触摸,就好像被触摸的视图是SurfaceView一样。我的整个思考方式可能是错误的,所以我在征求你的意见。

一些代码:

public GameSurfaceView(Context context) {
    super(context);
    GAME_STATE = GameState.LOADING;
    this.context = context;
    holder = getHolder();
    holder.addCallback(new SurfaceHolder.Callback() {

        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
        }

        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            Canvas c = holder.lockCanvas(null);
            onDraw(c);
            holder.unlockCanvasAndPost(c);
        }

        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        }
    });
}

SurfaceView onDraw():

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    canvas.drawRGB(30, 180, 30);
    for (Card card : user.getTableCards()) {
        card.draw(canvas);
    }
}

卡片onDraw():

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    canvas.drawBitmap(getBitmap(), x, y, null);
}

和onTouch

@Override
public boolean onTouch(View v, MotionEvent event) {
    Log.d("TOUCH", "Class: " + v.getClass().toString());
    if (v.getClass() == Card.class) {
        Log.d("CARD", "Touched: " + ((Card) v).getValue());
    }
    return true;
}

我总是记录SurfaceView课程。 这甚至是做这样的事情的正确方法吗?我需要检测同一类的各个对象的触摸..

我目前通过向每张卡添加类型Rect的成员然后循环并检查触摸的x和y是否包含在该矩形中来实现此目的,但这似乎是一种昂贵的方式,迭代每张卡(即使最多52张)并检查它..

由于

2 个答案:

答案 0 :(得分:5)

你混淆了两个不同的概念,我将在A)和B)中解释。

您有两种选择:

A)如果你想继续使用SurfaceView(这可能是游戏的正确选择,因为它可以让你更好地控制绘制事物的方式),你的Card对象应该扩展Drawable,而不是View。 Drawable是一个愚蠢的类,你只是绘制到画布或传递给小部件作为他们的背景等.Android不需要了解更多。在这种情况下,您需要检查自己打出的卡片,就像您描述的那样。 Android无法为您处理此问题。你用View而不是Drawable来做这个,这是错误的!或者至少是一个巨大的浪费。请参阅下文,了解如何使用视图正确完成此操作。

B)使用视图,它将为您处理触摸事件和许多其他事项。

View是一个复杂的类,应该存在于android的视图层次结构中。你正在使用它的方式就是丢掉它的大部分功能 - 当你直接将一个视图绘制到画布上时,android根本就没有真正意识到这个视图,所以它无法处理触摸事件。

基于视图的卡的正确实现可能如下所示:使用视图组作为基础,这是您在setContentView()中设置的。这个ViewGroup可能只是一个LinearLayout,或者如果你想在你的卡片上设置任意位置和大小,你可以使用AbsoluteView,虽然这已被弃用。

然后使用addView()将您的卡添加到ViewGroup。 Card视图在此范围内的定位由您传递给addView()的LayoutParams对象控制。这样android知道它的存在,并将处理这样的触摸事件:

  • 触摸事件首先进入您的ViewGroup
  • ViewGroup onTouchEvent会将事件向下发送到其子项的onTouchEvent(已通过addView()添加)。所以你只需在Card类中覆盖这个方法。你固有地知道调用了哪个Card的onTouchEvent,因为它被调用了对象本身。
  • 在您的Card的onTouchEvent中,您还可以让父母知道您通过返回true来处理触摸事件。如果您不这样做,父母可以代替处理该事件。

非常清楚:你没有将视图添加到SurfaceView,事实上,你不能,因为它不是一个ViewGroup。它只是一个复杂的View对象,允许您在其中执行任意绘制操作。但它始终是View层次结构的一个叶子,并且只能处理它自己的onTouchEvents,它不会将它发送给子节点,因为它不能有任何。

答案 1 :(得分:0)

你在SurfaceView上绘图卡片,就像在触摸你基本上碰到墙壁的图像时在墙上画图像一样,图像现在是墙壁的一部分,你无法将它们分开。 / p>

这个想法可能会有所帮助:

你有一张扩展View的卡片,为什么你不只是使用RelativeLayout而不是SurfaceView并将你的卡片添加到它(也许并排)。通过这种方式,您可以为每张卡片提供一个具体的视图,您可以为每个卡片注册一个OnClickListener并处理您的触摸事件......