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

Android人體部位點擊檢測:圖片熱區映射與自定義View實現方案

     編輯:程式設計綜合問答

需求:單張人體圖片(1160x638),點擊不同部位(頭、手、胸、腹、腿)彈出對應Toast。核心思路:**預定義部位矩形區域(相對圖片坐標),觸摸事件坐標轉換後碰撞檢測**。本文提供完整自定義View實現方案。

核心數據結構:部位元數據


class BodyPart {
    String name;        // "head", "left_arm"...
    String label;       // 顯示文本 "頭部", "左手臂"
    RectF bounds;       // 相對圖片原始尺寸的矩形區域 (left, top, right, bottom)
    // 可擴展:點擊動作、關聯資源ID等
}

// 初始化配置(可放JSON/assets/body_parts.json動態加載)
List parts = Arrays.asList(
    new BodyPart("head", "頭部", new RectF(400, 50, 760, 200)),
    new BodyPart("left_arm", "左手臂", new RectF(100, 250, 300, 400)),
    // ... 其他部位
);

自定義View實現


public class BodyMapView extends View {
    private Bitmap bodyBitmap;
    private List parts;
    private Matrix matrix = new Matrix(); // 圖片繪製變換矩陣
    private RectF drawRect = new RectF(); // 實際繪製區域

    public BodyMapView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init() {
        bodyBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.body_map);
        // 初始化 parts 數據...
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        // 計算圖片縮放居中繪製矩陣
        float scale = Math.min((float)w / bodyBitmap.getWidth(), (float)h / bodyBitmap.getHeight());
        matrix.setScale(scale, scale);
        matrix.postTranslate((w - bodyBitmap.getWidth() * scale) / 2, 
                             (h - bodyBitmap.getHeight() * scale) / 2);
        matrix.mapRect(drawRect, new RectF(0, 0, bodyBitmap.getWidth(), bodyBitmap.getHeight()));
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawBitmap(bodyBitmap, matrix, null);
        // 可選:調試繪製熱區邊框
        // for (BodyPart p : parts) { canvas.drawRect(transformRect(p.bounds), paint); }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            float touchX = event.getX();
            float touchY = event.getY();
            
            // 1. 檢查是否在圖片繪製區域內
            if (!drawRect.contains(touchX, touchY)) return true;
            
            // 2. 觸摸點映射回圖片原始坐標系
            float[] pts = {touchX, touchY};
            Matrix inverse = new Matrix();
            matrix.invert(inverse);
            inverse.mapPoints(pts);
            float imgX = pts[0], imgY = pts[1];
            
            // 3. 遍歷部位檢測碰撞
            for (BodyPart part : parts) {
                if (part.bounds.contains(imgX, imgY)) {
                    Toast.makeText(getContext(), part.label, Toast.LENGTH_SHORT).show();
                    // 可回調接口通知 Activity/Fragment
                    if (listener != null) listener.onPartClick(part);
                    return true;
                }
            }
        }
        return super.onTouchEvent(event);
    }

    // 輔助:矩陣變換 RectF
    private RectF transformRect(RectF src) {
        RectF dst = new RectF();
        matrix.mapRect(dst, src);
        return dst;
    }

    public interface OnPartClickListener {
        void onPartClick(BodyPart part);
    }
    private OnPartClickListener listener;
    public void setOnPartClickListener(OnPartClickListener l) { listener = l; }
}

關鍵技術點

  1. 坐標系轉換:觸摸點(View坐標) → `matrix.invert().mapPoints()` → 圖片原始坐標 → 與預定義`RectF`碰撞檢測。
  2. 自適應縮放**:`onSizeChanged`計算`Matrix`保證圖片異形屏適配,熱區定義基於**原圖坐標**,一次配置多處復用。
  3. 數據驅動**:部位配置外部化(JSON/XML),美術調整熱區無需改代碼。
  4. 性能**:僅觸摸時遍歷十幾個`RectF.contains()`,極輕量;繪製僅`drawBitmap`。

進階擴展

  • 不規則熱區:用`Path`替代`RectF`,`path.contains(x, y)`檢測。
  • 高亮反饋:點擊後在`onDraw`中繪製半透明覆蓋層/邊框動畫。
  • 多圖層:骨骼/肌肉/器官圖層疊加,通過圖層開關顯示。
  • 編輯器模式:長按拖拽調整熱區,導出JSON配置。

XML佈局使用



核心模式:原圖坐標定熱區,觸摸點逆矩陣映射回原圖,RectF/Path碰撞檢測,數據驅動UI。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved