Implementing Clickable Images

PSLab Android application is a feature rich compact app to user interface the PSLab hardware device. Similarly the PSLab device itself is a compact device with a plenty of features to replace almost all the analytical instruments in a school science lab. When a first time user takes the device and connect it with the Android app, there are so many pins labeled with abbreviations. This creates lots of complications unless the user checks the pinout diagram separately.

As a workaround a UI is proposed to integrate a layout containing the PSLab PCB image where user can click on each pin to get a dialog box explaining him what that specific pin is and what it does. This implementation can be done it two ways;

  • Using an Image map
  • Using (x,y) coordinates

The first implementation is more practical and can be applied with any device with any dimension. The latter requires some transformation to capture the correct position when user has clicked on a pin. So the first method will be implemented.

The idea behind using an image map is to have two images with exact dimensions on top of each other. The topmost image will be the color map which we create ourselves using unique colors at unique heat points. This image will have the visibility setting invisible as the main idea is to let the  user see a meaningful image and capture the positions using a secondary in the back end.

To make things much clear, let’s have a look at a color map image I am suggesting here for a general case.

If we overlap the color map with the PSLab layout, we will be able to detect where user has clicked using Android onTouchEvent.

@Override
public boolean onTouchEvent(MotionEvent ev) {
   final int action = ev.getAction();
   final int evX = (int) ev.getX();
   final int evY = (int) ev.getY();
   switch (action) {
       case MotionEvent.ACTION_UP :
         int touchColor = getHotspotColor (R.id.backgroundMap, evX, evY);
         /* Display the relevant pin description dialog box here */
         break;
   }
   return true;
}

 
Color of the clicked position can be captured using the following code;

public int getHotspotColor (int hotspotId, int x, int y) {
   ImageView img = (ImageView) findViewById (hotspotId);
   img.setDrawingCacheEnabled(true);
   Bitmap hotspots = Bitmap.createBitmap(img.getDrawingCache());
   img.setDrawingCacheEnabled(false);
   return hotspots.getPixel(x, y);
}

 
If we go into details, from the onTouchEvent we capture the (x,y) coordinates related to user click. Then this location is looked up for a unique color by creating a temporary bitmap and then getting the pixel value at the captured coordinate.

There is an error in this method as the height parameter always have an offset. This offset is introduced by the status bar and the action bar of the application. If we use this method directly, there will be an exception thrown out saying image height is less than the height defined by y.

Solving this issue involves calculating status bar and actionbar heights separately and then subtract them from the y coordinate.

Actionbar and status bar heights can be calculated as follows;

Rect rectangle = new Rect();
Window window = getWindow();
window.getDecorView().getWindowVisibleDisplayFrame(rectangle);
int statusBarHeight = rectangle.top;
int contentViewTop = window.findViewById(Window.ID_ANDROID_CONTENT).getTop();
int titleBarHeight= contentViewTop - statusBarHeight;

 
Using them, we can modify the captured coordinates as follows;

int touchColor = getHotspotColor (R.id.imageArea, evX, evY - statusBarHeight);

 
This way the exception is handled by adjusting the cursor position. Once this is done, it is all about displaying the correct pin description dialog box.

Reference:

Calculate status bar height: https://stackoverflow.com/questions/3407256/height-of-status-bar-in-android