首页 > 代码库 > 自己定义ImageView,实现点击之后算出点击的是身体的哪个部位

自己定义ImageView,实现点击之后算出点击的是身体的哪个部位

近期也是由于项目的原因,所以有机会接触到这边的算法。 此文重点不是怎样实现的思路和原理, 有须要的同事能够借鉴一下

废话不多说,直接上代码:

<span style="font-size:18px;"><span style="font-size:18px;">public class MyImage extends ImageView {

    private DisplayMetrics dm;

    private int bodyImageViewHeight = 0;
    private int bodyImageViewWidth = 0;

    public MyImage(Context context) {
        super(context);
    }

    public MyImage(Context context, AttributeSet attrs) {
        super(context, attrs);
        dm = context.getResources().getDisplayMetrics();
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {

        int x = (int) event.getX();
        int y = (int) event.getY();

        //初始化各个部位的范围
        initParametersForRegion();

        if(isTouchPointInTransparent(x, y)) {
            Log.e("mcoy", "the point is in transparent area now");
        } else {
            positionType position = pointToPosition(x, y);
            Log.e("mcoy", "the position is " + position);
        }

        return super.onTouchEvent(event);
    }

    private enum positionType{
        REGION_FRONT_HAND,
        REGION_FRONT_HEAD,
        REGION_FRONT_CHEST,
        REGION_FRONT_WAIST,
        REGION_FRONT_LEG
    }

    private positionType pointToPosition(int x, int y) {
        if(x < mHandX1 || x > mHandX2)
            return positionType.REGION_FRONT_HAND;
        else if (y < mHeadY)
            return positionType.REGION_FRONT_HEAD;
        else if(y < mChestY)
            return positionType.REGION_FRONT_CHEST;
        else if(y < mWaistY)
            return positionType.REGION_FRONT_WAIST;
        else
            return positionType.REGION_FRONT_LEG;
    }

    /**
     *
     * @param x
     * @param y
     * @return 推断点击区域是否在透明区域
     */
    private boolean isTouchPointInTransparent(int x, int y) {

        int paddingLeft = this.getPaddingLeft();
        int paddingTop = this.getPaddingTop();

        int imageHeight = this.getHeight();
        int imageWidth = this.getWidth();

        Drawable drawable = this.getDrawable();
        Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();

        int intrinsicHeight = drawable.getIntrinsicHeight();
        int intrinsicWidth = drawable.getIntrinsicWidth();

        int locationInBitmapX = (x - paddingLeft) * intrinsicWidth / imageWidth;
        int locationInBitmapY = (y - paddingTop) * intrinsicHeight / imageHeight;

        int pixel = bitmap.getPixel(locationInBitmapX, locationInBitmapY);

        Log.e("mcoy", "x is " + x);
        Log.e("mcoy", "y is " + y);
        Log.e("mcoy", "imageHeight is " + imageHeight);
        Log.e("mcoy", "imageWidth is " + imageWidth);
        Log.e("mcoy", "intrinsicHeight is " + intrinsicHeight);
        Log.e("mcoy", "intrinsicWidth is " + intrinsicWidth);
        Log.e("mcoy", "locationInBitmapX is " + locationInBitmapX);
        Log.e("mcoy", "locationInBitmapY is " + locationInBitmapY);
        Log.e("mcoy", "actualBitmapX is " + locationInBitmapX / dm.density);
        Log.e("mcoy", "actualBitmapY is " + locationInBitmapY / dm.density);
        Log.e("mcoy", "pixel is " + pixel);

        return pixel == 0;
    }

    private int mHeadY;
    private int mHandX1;
    private int mHandX2;
    private int mChestY;
    private int mWaistY;

    //下面数据须要同UI同事沟通好每一个部位定义的范围。或者自己手动量一下
    private final int HEAD_AREA = 130;
    private final int LEFT_HAND_AREA = 126;
    private final int RIGHT_HAND_AREA = 280;
    private final int CHEST_AREA = 260;
    private final int WAIST_AREA = 417;

    private void initParametersForRegion() {

        if(bodyImageViewHeight != this.getHeight()) {

            bodyImageViewHeight = this.getHeight();
            bodyImageViewWidth = this.getWidth();
            int imageIntrinsicHeight = this.getDrawable().getIntrinsicHeight();
            int imageIntrinsicWidht = this.getDrawable().getIntrinsicWidth();
            Log.e("danny", "bodyImageViewHeight is " + bodyImageViewHeight);
            Log.e("danny", "bodyImageViewWidth is " + bodyImageViewWidth);
            Log.e("danny", "imageIntrinsicHeight is " + imageIntrinsicHeight);
            Log.e("danny", "imageIntrinsicWidht is " + imageIntrinsicWidht);

            mHeadY = DensityUtil.dip2px(getContext(), HEAD_AREA) * bodyImageViewHeight / imageIntrinsicHeight
                    + this.getPaddingTop();
            mHandX1 = DensityUtil.dip2px(getContext(), LEFT_HAND_AREA) * bodyImageViewWidth / imageIntrinsicWidht
                    + this.getPaddingLeft();
            mHandX2 = DensityUtil.dip2px(getContext(), RIGHT_HAND_AREA) * bodyImageViewWidth / imageIntrinsicWidht
                    + this.getPaddingLeft();
            mChestY = DensityUtil.dip2px(getContext(), CHEST_AREA) * bodyImageViewHeight / imageIntrinsicHeight
                    + this.getPaddingTop();
            mWaistY = DensityUtil.dip2px(getContext(), WAIST_AREA) * bodyImageViewHeight / imageIntrinsicHeight
                    + this.getPaddingTop();

            Log.e("danny", "mHeadY is " + mHeadY);
            Log.e("danny", "mHandX1 is " + mHandX1);
            Log.e("danny", "mHandX2 is " + mHandX2);
            Log.e("danny", "mChestY is " + mChestY);
            Log.e("danny", "mWaistY is " + mWaistY);

        }
    }
}</span></span>

代码非常easy, 就是一个自己实现的ImageView, 可是有几点须要注意的点:

1 图片须要跟UI同事沟通好对应坐标(认真看完代码之后就会知道原因), 假设换图片的话。那HEAD_AREA等值可能须要又一次定义

2 算法思路---在不同的desity的的设备上。 我们都能够算出图片相应的drawable的width/height,而图片缩放或者是放大是依照比例缩放/放大, 因此我们能够得出例如以下等式:

touchX / imageWidth = positonInBitmap / drawable.getIntransicWidth ;

==> positonInBitmap = touchX * drawable.getIntransicWidth / imageWidth;

touchX是点击在ImageView上的x坐标;imageWidth是图片的宽度。positionInBitmap是touchX映射在ImageView所相应drawable上的x坐标(这句话有点拗口,能够细致想一下)


下面是xml文件:

<span style="font-size:18px;"><span style="font-size:18px;"><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.mcoy.pixelinbitmaptest.MainActivity" >

    <TextView
        android:id="@+id/tv"
        android:layout_width="wrap_content"
        android:layout_height="80dp"
        android:text="@string/hello_world" />

    <com.example.jiangxinxing.views.MyImage
        android:id="@+id/iv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:adjustViewBounds="true"
        android:scaleType="fitXY"
        android:src=http://www.mamicode.com/"@drawable/man_front">
也有一点须要注意:

须要将adjustViewBounds属性设置为true。这样会调整ImageView的界限来保持图像纵横比不变


demo下载链接:http://download.csdn.net/detail/zxm317122667/9000969

自己定义ImageView,实现点击之后算出点击的是身体的哪个部位