最近也是因为项目的原因,所以有机会接触到这边的算法。 此文重点不是如何实现的思路和原理, 有需要的同事可以借鉴一下
废话不多说,直接上代码:
<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>
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="@drawable/man_front" android:layout_below="@+id/tv" /> </RelativeLayout></span></span>
需要将adjustViewBounds属性设置为true,这样会调整ImageView的界限来保持图像纵横比不变
demo下载链接:http://download.csdn.net/detail/zxm317122667/9000969