如何为特定的 Drawable 创建事件?

How to create event for specific Drawable?

当我接触到带有钻石的卡片时,我必须创建一个事件。这是因为我的目标是在我触摸它们时获得分数。如果我触摸卡片(例如背景或带有椭圆形的卡片),则不会发生任何事情。

onTouchEvent()的方法我已经通过了,但是它在整个屏幕上都是通用的,而不仅仅是一个Drawable。

GameView.java

package com.example.game;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Shader;
import android.graphics.drawable.Drawable;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

import java.util.Arrays;
import java.util.Random;

public class GameView extends View {

    private static final String TAG = "TAG_GameView";
    private final Drawable diamond;
    private final Drawable circle;

    private final boolean[] columnFree;
    private final Paint background;

    int column;
    int a;
    int b;

    int[] x;
    int[] y;
    int[] speed;
    int[] type;

    public GameView(Context context) {
        super(context);
        diamond = context.getResources().getDrawable(R.drawable.diamond);
        circle = context.getResources().getDrawable(R.drawable.circle);

        background = new Paint();

        column = 4;
        x = new int[column];
        y = new int[10*column];
        speed = new int[column];
        type = new int[10*column];
        columnFree = new boolean[column];

        Arrays.fill(y, 9999);
        Arrays.fill(type, 0);
        for (int i=0; i<speed.length; i++) {
            speed[i]=10*(1+(new Random().nextInt(2)));
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        background.setShader(new LinearGradient(0,0,0,getHeight(),Color.BLUE,Color.CYAN, Shader.TileMode.CLAMP));
        canvas.drawPaint(background);

        a = getWidth()*8/(9*column+1);
        b = a*diamond.getIntrinsicHeight()/diamond.getIntrinsicWidth();

        for (int i = 0; i < x.length; i++) {
            x[i] = a/8*(i+1) + a*i;
            columnFree[i] = true;
        }

        for (int i = 0; i < y.length; i++) {
            y[i] += speed[i%column];
            if (y[i]<b) {
                columnFree[i%column]=false;
            }
        }

        for (int i = 0; i < y.length; i++) {
            if ((y[i] > getHeight() && columnFree[i % column]) == true) {
                //For 40% chance of true
                if (new Random().nextInt(50) < 1) {
                    y[i] = -b;
                    columnFree[i%column] = false;
                    type[i] = new Random().nextInt(2);
                    Log.i(TAG, String.valueOf(type[i]));
                }
            } else {
                if (type[i]==0){
                    diamond.setBounds(x[i%column], y[i],x[i%column]+a,y[i]+b);
                    diamond.draw(canvas);
                } else {
                    circle.setBounds(x[i%column], y[i],x[i%column]+a,y[i]+b);
                    circle.draw(canvas);
                }
            }
        }

    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            Arrays.fill(speed, 0);
        }
        return super.onTouchEvent(event);
    }
}

正如@CommonsWare 建议的那样,您需要跟踪当前出现在屏幕上的所有卡牌位置(或所有卡牌位置),并在onTouchEvent() 中检查事件是否发生在钻石卡上

像这样的跟踪卡:

Map<RectF, Drawable> cards = new HashMap();

// in onDraw method when you draw card also add it to that map

@Override
protected void onDraw(Canvas canvas){
//...

    if (type[i]==0){
        diamond.setBounds(x[i%column], y[i],x[i%column]+a,y[i]+b);
        diamond.draw(canvas);
        cards.put(new RectF(x[i%column], y[i],x[i%column]+a,y[i]+b), diamond)
    } else {
        circle.setBounds(x[i%column], y[i],x[i%column]+a,y[i]+b);
        circle.draw(canvas);
        cards.put(new RectF(x[i%column], y[i],x[i%column]+a,y[i]+b), diamond)
    }
//...
}

然后在onTouchEvent()

int points = 0;

@Override
public boolean onTouchEvent(MotionEvent event) {
    //...
    float x = event.getX();
    float y = event.getY();
    for (Map.Entry<RectF, Drawable> entry : cards.entrySet()) {
        if (entry.getKey().contains(x, y) && entry.getValue() == diamond) 
            points++;
    }
    //...
}

你也可以通过引入一些boolean值(检查它是否被点击)和卡片id(以区别于其他卡片)并存储它们来调整用法,使一张卡片只获得一次积分连同卡片矩形和 Drawable.

或者你可以从点击钻石卡的位置开始清除卡片中的列,直到列的末尾(这样它就不会在下一帧重绘)

希望对您有所帮助