Sunday, May 6, 2012

Map the touch position with a mask, version II.


In the last exercise "Map the touch position with a mask", I tried to map a touched position from screen to a mask bitmap. It's difficult to align the image of a ImageView and the bitmap!

It's another more flexible approach: I create another invisible custom ImageView, MaskView. It have the same layout assigned for TouchView. It use the mask image as background. TouchView is resumed to use the display image as background. Such that I can get background color from MaskView to map with touch position in TouchView.

Doing so, I can easy to allocate it in any place, any size.

Map the touch position with a mask


Implement a custom ImageView, MaskView.java
package com.exercise.AndroidDetechTouch;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.util.AttributeSet;
import android.widget.ImageView;

public class MaskView extends ImageView {

 Bitmap bitmap;
 double bmWidth, bmHeight;
 
 public MaskView(Context context) {
  super(context);
  init();
 }

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

 public MaskView(Context context, AttributeSet attrs, int defStyle) {
  super(context, attrs, defStyle);
  init();
 }
 
 private void init(){
  bitmap = ((BitmapDrawable)getBackground()).getBitmap();
  bmWidth = (double)bitmap.getWidth();
  bmHeight = (double)bitmap.getHeight(); 
 }
 
 public int getColor(float x, float y){
  if ( x < 0 || y < 0 || x > (float)getWidth() || y > (float)getHeight()){
   return 0; //Invalid, return 0 
  }else{
   //Convert touched x, y on View to on Bitmap
   int xBm = (int)(x * (bmWidth / (double)getWidth()));
   int yBm = (int)(y * (bmHeight / (double)getHeight()));
   return bitmap.getPixel(xBm, yBm); 
  }
 }

}


Modify TouchView.java, it get pixel color from MaskView indirectly.
package com.exercise.AndroidDetechTouch;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.drawable.BitmapDrawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.ImageView;

public class TouchView extends ImageView {
 
 Bitmap bitmap, mask;
 double bmWidth, bmHeight; 
 
 String touchInfo;
 float touchX, touchY;
 
 String part;

 public TouchView(Context context) {
  super(context);
  // TODO Auto-generated constructor stub
  init();
 }

 public TouchView(Context context, AttributeSet attrs) {
  super(context, attrs);
  // TODO Auto-generated constructor stub
  init();
 }

 public TouchView(Context context, AttributeSet attrs, int defStyle) {
  super(context, attrs, defStyle);
  // TODO Auto-generated constructor stub
  init();
 }
 
 private void init(){

  //bitmap = ((BitmapDrawable)getDrawable()).getBitmap();
  //mask = BitmapFactory.decodeResource(getResources(), R.drawable.android_mask);
  //bmWidth = (double)bitmap.getWidth();
  //bmHeight = (double)bitmap.getHeight();
 }

 @Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  // TODO Auto-generated method stub
  setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec),
       MeasureSpec.getSize(heightMeasureSpec));
 }

 @Override
 public boolean onTouchEvent(MotionEvent event) {
  // TODO Auto-generated method stub

  switch(event.getAction()){
  case MotionEvent.ACTION_DOWN:
  case MotionEvent.ACTION_MOVE:
   touchX = event.getX();
   touchY = event.getY();

   //long maskColor = getColor(touchX, touchY);
   long maskColor = getMaskColor(touchX, touchY);
   
   //Match the color in Mask bitmap
   if(maskColor == Color.RED){
    touchInfo = "Heart";
   }else if(maskColor == Color.GREEN){
    touchInfo = "Head";
   }else if(maskColor == Color.BLUE){
    touchInfo = "Body";
   }else if(maskColor == -256){
    touchInfo = "Hand";
   }else if(maskColor == -16711681){
    touchInfo = "Foot";
   }else{
    touchInfo = "";
   }

   ((AndroidDetechTouchActivity)getContext()).updateMsg(touchInfo, touchX, touchY, (int)maskColor);
   return true;

  default:
   return false;
  }

 }
 
 private long getMaskColor(float x, float y){
  AndroidDetechTouchActivity parent = (AndroidDetechTouchActivity)(getContext());
     return parent.getMaskColor(x, y);
    }
 

 private long getColor(float x, float y){

  if ( x < 0 || y < 0 || x > (float)getWidth() || y > (float)getHeight()){
   return 0; //Invalid, return 0
  }else{
   //Convert touched x, y on View to on Bitmap
   int xBm = (int)(x * (bmWidth / (double)getWidth()));
      int yBm = (int)(y * (bmHeight / (double)getHeight()));

   return mask.getPixel(xBm, yBm);
  }
 }

}


Modify AndroidDetechTouchActivity.java
package com.exercise.AndroidDetechTouch;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.widget.ImageView;

public class AndroidDetechTouchActivity extends Activity {

 TouchView myAndroid;
 InfoView infoView;
 
 MaskView myMask;
 
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        myAndroid = (TouchView)findViewById(R.id.myandroid);
        infoView = (InfoView)findViewById(R.id.infoview);
        myMask = (MaskView)findViewById(R.id.mymask);

    }

    public void updateMsg(String t_info, float t_x, float t_y, int t_c){

     infoView.updateInfo(t_info, t_x, t_y, t_c);
     
    }
    
    public void clearMsg(){

     infoView.clearInfo();
     
    }
    
    public long getMaskColor(float x, float y){
     return myMask.getColor(x, y);
    }

}


Modify main.xml to add MaskView. Both MaskView and TouchView set android:background instead of android:src. Also set MaskView invisible.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/hello" />
    <LinearLayout 
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:gravity="bottom"
        >
 <FrameLayout 
        android:layout_width="fill_parent"
        android:layout_height="250dp"
     >
  <com.exercise.AndroidDetechTouch.MaskView
         android:id="@+id/mymask"
         android:layout_width="fill_parent"
         android:layout_height="fill_parent"
         android:background="@drawable/android_mask"
         android:visibility="invisible"
         />
     <com.exercise.AndroidDetechTouch.TouchView
         android:id="@+id/myandroid"
         android:layout_width="fill_parent"
         android:layout_height="fill_parent"
         android:background="@drawable/android"
         />
     <com.exercise.AndroidDetechTouch.InfoView
         android:id="@+id/infoview"
         android:layout_width="fill_parent"
         android:layout_height="fill_parent"
         />

 </FrameLayout>
 </LinearLayout>
</LinearLayout>


Download the files.

2 comments:

stephy yan said...

Sorry, I'm trying to ask stupid question again.. May i know where you paint the image in bitmap?

Erik said...

hello stephy,

Do you means where is the code to add the bitmap?

The statement "android:background=..." in main.xml.