【问题标题】:How to tell if an X and Y coordinate are inside my button?如何判断 X 和 Y 坐标是否在我的按钮内?
【发布时间】:2020-10-20 18:21:29
【问题描述】:

我费了很大的力气才使位图覆盖在屏幕上。我也可以获得触摸输入,但是它可以在屏幕上的任何地方获得触摸输入。

我想知道如何检查触摸是否在屏幕上可见的位图上。

服务和视图类如下。想了又想,还是想不出办法:(

package <package>;

import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.os.IBinder;
import android.support.v4.app.NotificationCompat;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.Toast;

public class MyService extends Service {
    ButtonView mView;
    Bitmap bit;

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();

        bit = BitmapFactory.decodeResource(getResources(), R.drawable.button);

        NotificationCompat.Builder builder = new NotificationCompat.Builder(
                this);
        builder.setContentTitle("Ingress Tools Running");
        builder.setContentText("Click to stop Ingress Tools");
        builder.setSmallIcon(R.drawable.ic_launcher);
        builder.setContentIntent(PendingIntent.getActivity(this, 0, new Intent(
                this, StopActivity.class), 0));
        NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        manager.notify(1, builder.build());

        mView = new ButtonView(this, bit);
        WindowManager.LayoutParams params = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.FILL_PARENT,
                WindowManager.LayoutParams.FILL_PARENT,
                WindowManager.LayoutParams.TYPE_PHONE,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                        | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                        | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
                PixelFormat.TRANSLUCENT);
        params.gravity = Gravity.RIGHT;
        params.setTitle("Load Average");
        WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
        wm.addView(mView, params);

    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Toast.makeText(getBaseContext(), "onDestroy", Toast.LENGTH_LONG).show();
        if (mView != null) {
            ((WindowManager) getSystemService(WINDOW_SERVICE))
                    .removeView(mView);
            mView = null;
        }
    }
}

class ButtonView extends ViewGroup {
    private Paint mLoadPaint;
    private Rect r;
    private Bitmap bit;

    public ButtonView(Context context, Bitmap bit) {
        super(context);
        Toast.makeText(context, "HUDView", Toast.LENGTH_LONG).show();

        mLoadPaint = new Paint();
        mLoadPaint.setAntiAlias(true);
        mLoadPaint.setTextSize(10);
        mLoadPaint.setARGB(255, 255, 0, 0);
        r = new Rect();
        r.set(380, 134, 468, 213);
        this.bit = bit;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //canvas.drawColor(Color.BLACK);

        canvas.drawBitmap(bit, 100, 100, null);
    }

    @Override
    protected void onLayout(boolean arg0, int arg1, int arg2, int arg3, int arg4) {
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {

        int area = bit.getWidth() * bit.getHeight();


        //if (event.getY() <= maxY && event.getX() <= maxX) {
            Toast.makeText(getContext(), "Open tools: ", Toast.LENGTH_LONG)
                    .show();

        //}
        return true;

    }
}

【问题讨论】:

    标签: java android


    【解决方案1】:

    这适用于任何视图

    @Override
        public boolean dispatchTouchEvent(MotionEvent event) {
    
                if (event.getAction() == MotionEvent.ACTION_UP) {
                    if (inViewInBounds(myButtonView, (int) event.getRawX(), (int) event.getRawY())) {
                        // User moved outside bounds
                        Log.e("dispatchTouchEvent", "you touched inside button");
                    } else {
                        Log.e("dispatchTouchEvent", "you touched outside button");
                    }
    
            }
            return super.dispatchTouchEvent(event);
        }
    
     Rect outRect = new Rect();
        int[] location = new int[2];
    
    
     private boolean inViewInBounds(View view, int x, int y) {
            view.getDrawingRect(outRect);
            view.getLocationOnScreen(location);
            outRect.offset(location[0], location[1]);
            return outRect.contains(x, y);
        }
    

    【讨论】:

    • 有效,但我不明白这些功能。为什么我要在调用 View::getDrawingRect 后调用 View::getLocationOnScreen? Rect 不应该也有 x y 位置吗?另外我猜 Rect::offset() 会重新定位矩形,但我不太明白。
    【解决方案2】:

    考虑直接使用FrameLayout(或ViewGroup 的任何其他子类)而不是ViewGroup。因为您当前对onLayout 方法的实现不正确,这将导致您在显示子视图时出现问题。

    现在,更接近您的问题。您应该初始化Rect 并只存储Bitmap 的左、上、右和下位置。如我所见,目前您已初始化 r 变量,但没有在任何地方使用它。

    所以,你可以这样初始化它:

    r = new Rect(100, 100, 100 + bit.getWidth(), 100 + bit.getHeight());
    

    现在您可以在onTouchEvent 中查看:

    r.contains((int) event.getX(), (int) event.getY());
    

    【讨论】:

    • 嗯,这行得通,但现在没有其他东西接收到触摸事件。例如,我无法单击屏幕上的其他任何内容(尽管这可能在我添加此内容之前发生)。
    • @LiamW 如果您希望您的 MotionEvent 被进一步传播,那么您应该从 onTouchEvent 返回 false
    • 我确实在 if 语句之外返回 false,但如果我触摸图像之外什么都不会发生。
    • @LiamW 这可能是因为您的视图(和您的窗口)是FILL_PARENT
    【解决方案3】:
    Rect rect = new Rect(); 
    getHitRect(rect);
    if (rect.contains((int) event.getX(), (int) event.getY())) {}
    

    您可以使用 getHitRect(Rect)。它返回父坐标中的 Hit 矩形。 Here文档

    【讨论】:

    • 通常,这个答案是要走的路。虽然,他画的是Bitmap而不是View,所以getHitRect不能用。
    【解决方案4】:

    在您要检查的按钮上使用带有方法if(r.contains(x, y)) 的if 语句。当 x 和 y 点在矩形 r 内时,此方法将返回 true。您还可以在该类中创建公共方法,以便您可以在 ButtonView 类之外使用按钮对象引用访问它。

    【讨论】:

      【解决方案5】:
      // We assume MotionEvent is from the direct View parent so we are in the same co-ordindate space
      fun View.isWithinBounds(event: MotionEvent): Boolean {
          val rect = Rect(x.roundToInt(), y.roundToInt(), (x + width).roundToInt(), (y + height).roundToInt())
          return rect.contains(event.x.roundToInt(), event.y.roundToInt())
      }
      

      【讨论】:

        【解决方案6】:

        当“触摸事件”发生时,它会遍历所有视图的树。 F.e.如果你有线性布局和 ImageView 并且用户在 ImageView 上触摸屏幕,则触摸事件拦截,首先它将在 LinearLayour 处处理,然后在 ImageView 处处理。

        如果您想阻止事件 f.e.在位图上,那么您应该覆盖位图的 onTouchEvent 并返回真值。这意味着你处理了这个事件,它不适用于 LinearLayout。

        image.setOnTouchListener( new View.OnTouchListener() {
                    @Override
                    public boolean onTouch(View view, MotionEvent motionEvent) {
                        return true;  // attentively read documentation for onTouc interface
                    }
                });
        

        【讨论】:

          猜你喜欢
          • 2021-03-14
          • 1970-01-01
          • 1970-01-01
          • 2014-12-17
          • 2019-06-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-12-04
          相关资源
          最近更新 更多