首先介绍一下功能:点击人体部位实现微交互,并进行页面跳转。
此功能共有三类人,男人女人和小孩,同时又结合了前身,后背,及头部放大,故有3*3种情况,这里我们使用自定义View去解决。
首先我们自定义一个BodyView继承于View。
- public BodyView(Context context) {
- this(context, null);
- }
-
- public BodyView(Context context, AttributeSet paramAttributeSet) {
- this(context, paramAttributeSet, 0);
- }
-
- public BodyView(Context context, AttributeSet paramAttributeSet, int paramInt) {
- super(context, paramAttributeSet, paramInt);
- this.mContext = context;
- init();
- }
- private void init() {
- float density = getResources().getDisplayMetrics().density;
- BitmapFactory.Options localOptions = new BitmapFactory.Options();
- localOptions.inJustDecodeBounds = true;
- BitmapFactory.decodeResource(getResources(), R.mipmap.man_front, localOptions);
- mManFrontWidth = ((int) (density * localOptions.outWidth / 2.0F));
- mManFrontHeight = ((int) (density * localOptions.outHeight / 2.0F));
- BitmapFactory.decodeResource(getResources(), R.mipmap.man_bigface, localOptions);
- mHeadWidth = ((int) (density * localOptions.outWidth / 2.0F));
- mHeadHeight = ((int) (density * localOptions.outHeight / 2.0F));
- mPaint = new Paint();
- mPaint.setAntiAlias(true);
- mPaint.setColor(Color.WHITE);
- mPaint.setStrokeWidth(5.0F);
- mInitAreaRunnable = new InitAreaRunnable(this);
- }
我们做的是drawBitmap,这里是对图片和画笔做一些设置,其中关键的是我们创建了一个子线程,通过runnable我们可以读取一些坐标及偏移量的数据
二、接下来我们看看我们创建的Runnable做了些什么:
- switch (mCrowd.ordinal()) {
- case 1:
- if (mIsHead) {
- if (mManHeadAreaList.size() == 0 || isCache) {
- mCurrentAreaList = getBodyAreaFromFile("guideBody/man_bigface", true);
- }
- } else if (mIsBack) {
- if (mManBackAreaList.size() == 0 || isCache) {
- mCurrentAreaList = getBodyAreaFromFile("guideBody/man_back", false);
- }
- } else {
- if (mManFrontAreaList.size() == 0 || isCache) {
- mCurrentAreaList = getBodyAreaFromFile("guideBody/man_front", false);
- }
- }
- break;
- case 2:
- if (mIsHead) {
- if (mWomanHeadAreaList.size() == 0 || isCache) {
- mCurrentAreaList = getBodyAreaFromFile("guideBody/woman_bigface", true);
- }
- } else if (mIsBack) {
- if (mWomanBackAreaList.size() == 0 || isCache) {
- mCurrentAreaList = getBodyAreaFromFile("guideBody/woman_back", false);
- }
- } else {
- if (mWomanFrontAreaList.size() == 0 || isCache) {
- mCurrentAreaList = getBodyAreaFromFile("guideBody/woman_front", false);
- }
- }
- break;
- case 3:
- if (mIsHead) {
- if (mKidHeadAreaList.size() == 0 || isCache) {
- mCurrentAreaList = getBodyAreaFromFile("guideBody/kid_bigface", true);
- }
-
- } else if (mIsBack) {
- if (mKidBackAreaList.size() == 0 || isCache) {
- mCurrentAreaList = getBodyAreaFromFile("guideBody/kid_back", false);
- }
-
- } else {
- if (mKidFrontAreaList.size() == 0 || isCache) {
- mCurrentAreaList = getBodyAreaFromFile("guideBody/kid_front", false);
- }
- }
- }
先不管switch case语句,我们在这里读取了File文件保存的位图的偏移量和有效点击区域的数据。
方法如下:
- private List getBodyAreaFromFile(String paramString, boolean isHead) {
- ArrayList bodyAreaList = new ArrayList();
- try {
- JSONArray localJSONArray1 = new JSONArray(new FileUtil().readFromAssets(paramString));
- for (int i = 0; i < localJSONArray1.length(); i++) {
- JSONObject localJSONObject1 = localJSONArray1.optJSONObject(i);
- BodyArea bodyArea = new BodyArea();
- if (localJSONObject1 != null) {
- bodyArea.bodyId = localJSONObject1.optInt("bid");
- bodyArea.mipmapId = getResources().getIdentifier("intelligence_highlight_0" + String.valueOf(bodyArea.bodyId), "mipmap", getContext().getPackageName());
- bodyArea.bodyPart = BodyPart.values()[(bodyArea.bodyId % 100)];
- }
- JSONObject localJSONObject2 = localJSONObject1.optJSONObject("offset");
- if (localJSONObject2 != null) {
- bodyArea.areaPoint = new AreaPoint(this, localJSONObject2.optInt("x"), localJSONObject2.optInt("y"), isHead);
- }
- JSONArray localJSONArray2 = localJSONObject1.optJSONArray("polygon");
- for (int j = 0; j < localJSONArray2.length(); j++) {
- JSONObject localJSONObject3 = localJSONArray2.optJSONObject(j);
- if (localJSONObject3 != null) {
- AreaPoint areaPoint = new AreaPoint(this, localJSONObject3.optInt("x"), localJSONObject3.optInt("y"), isHead);
- bodyArea.partPolygon.add(areaPoint);
- }
- }
- bodyAreaList.add(bodyArea);
- }
- } catch (JSONException e) {
- e.printStackTrace();
- }
-
- return bodyAreaList;
- }
- /**
- * 热区对象
- */
- class BodyArea {
- public int bodyId = 0;
- public int mipmapId = R.mipmap.google;
- public BodyPart bodyPart = BodyPart.HEAD;
- public AreaPoint areaPoint = new AreaPoint();
- public List
partPolygon = new ArrayList(); -
- public String toString() {
- return "{bodyId=" + bodyId + ",mipmapId=" + mipmapId + ",bodyPart=" + bodyPart.toString() + "}";
- }
- }
我们对用户的触摸点击称之为热区,当然热区是个范围值,这里我们用一个List四、监听用户的onTouchEvent事件
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- if (!this.mEnableFlag) {
- return super.onTouchEvent(event);
- }
-
- switch (event.getAction()) {
- case MotionEvent.ACTION_DOWN:
- case MotionEvent.ACTION_MOVE:
- mXDown = event.getX();
- mYDown = event.getY();
- parseTouchEvent(new Point((int) mXDown, (int) mYDown));
- break;
- case MotionEvent.ACTION_UP:
- onActionUp();
- break;
- }
- return true;
- }
在这里我们通过一个算法去计算用户触摸的点是否在矩阵内,
- private void parseTouchEvent(Point point) {
- if (mCurrentAreaList != null) {
- Iterator
iterator = mCurrentAreaList.iterator(); -
- while (iterator.hasNext()) {
- BodyArea bodyArea = iterator.next();
- if (bodyArea.partPolygon != null && isPointInPolygon(point, bodyArea.partPolygon)) {
- mCurrentBodyArea = bodyArea;
- invalidate();
- break;
- } else {
- mCurrentBodyArea = null;
- invalidate();
- }
- }
- }
- }
根据用户的点击重绘界面。