首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

Android 自定義 View 點擊事件失效?觸摸分發機制與解決方案

     編輯:程式設計綜合問答

問題現象

自定義 MyView 繪製小圖標,設置 setOnClickListener 後,**點擊螢幕任意位置都會觸發**,而非僅限圖標區域。

根本原因

  • View 預設佔滿父容器(FrameLayout)整個區域。
  • onDraw 僅在 (830,880) 繪製圖標,**但 View 邊界未裁剪**,點擊事件分發給整個 View 矩形區域。
  • 未重寫 onTouchEvent 判斷觸摸點是否在圖標實際繪製區域內。

解決方案一:重寫 onTouchEvent 精準判斷(推薦)

class MyView extends View {
    private Rect iconRect = new Rect(830, 880, 890, 980); // 圖標實際區域

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_UP) {
            float x = event.getX(), y = event.getY();
            if (iconRect.contains((int)x, (int)y)) {
                performClick();  // 觸發標準點擊流程(含 OnClickListener)
                return true;
            }
        }
        return super.onTouchEvent(event);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.point);
        canvas.drawBitmap(bitmap, null, iconRect, null);
    }
}

解決方案二:裁剪 View 邊界至圖標大小(佈局配合)

在 onMeasure 中指定 View 大小為圖標尺寸,父容器用 layout_gravity 定位:

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    setMeasuredDimension(60, 100); // 圖標寬高
}

佈局 XML:

<FrameLayout ...>
    <com.example.MyView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="top|left"
        android:layout_marginLeft="830dp"
        android:layout_marginTop="880dp" />
</FrameLayout>

進階:讓圖標「跳動」起來(動畫)

// 在 onClick 或 performClick 內啟動
ObjectAnimator animator = ObjectAnimator.ofFloat(myView, "translationY", 0, -20, 0);
animator.setDuration(300);
animator.setInterpolator(new BounceInterpolator());
animator.start();

// 或縮放動畫
AnimatorSet set = new AnimatorSet();
set.playTogether(
    ObjectAnimator.ofFloat(myView, "scaleX", 1f, 1.3f, 1f),
    ObjectAnimator.ofFloat(myView, "scaleY", 1f, 1.3f, 1f)
);
set.setDuration(200).start();

核心知識點總結

  1. View 邊界 ≠ 繪製內容邊界:點擊響應區域由 View 矩形決定,非 onDraw 實際繪製區域。
  2. 觸摸分發鏈:dispatchTouchEvent → onInterceptTouchEvent → onTouchEvent,重寫 onTouchEvent 返回 true 表示消費事件。
  3. performClick():標準點擊入口,會觸發 OnClickListener、無障礙服務、狀態變更,優於直接調用回調。
  4. HitRect 擴大點擊區域:setTouchDelegate 可在不改變視覺大小前提下擴大響應區,適合小圖標。

掌握觸摸分發與幾何判斷,自定義 View 交互不再「全屏生效」。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved