20

I need to display a pretty image of a map of Europe, and I want my app to, e.g. bring up a different activity, when the user clicks each country - each country on the map needs to have a different onClickListener (or equivalent).

Essentially, I need to be able to call a different function when the user taps on France rather than Spain in an image such as this: http://commons.wikimedia.org/wiki/File:Blank_map_of_Europe_cropped.svg

How would I best go about this on Android?

I've got ideas, but there may be some simple way that I'm overlooking.

Many thanks in advance!

Cheers, r3mo

r3mo
  • 547
  • 1
  • 8
  • 19
  • How on earth would you be able to deduce the country from the clicked point? At best the listener would know the screen coordinates and that's all. It would have no idea where the national boundaries were on screen – NickT Oct 18 '10 at 16:29
  • 2
    Indeed, the listener would only know the coordinates clicked. Two ways: Have the map be composed of many images with listeners, one for each country, all overlapping to some extent so the map looks correct. Perhaps there is some method to do this? Alternatively, I'll be colouring each country just slightly differently (1 bit), so that they all look the same, but I can check the colour at the image coordinate clicked and look that up in a table to find what country that colour corresponds to. Though I appreciate you taking the time to comment, perhaps someone else can try to be more helpful? – r3mo Oct 18 '10 at 18:18
  • Possible duplicate of [clickable area of image](http://stackoverflow.com/questions/16670774/clickable-area-of-image) – Lukas Lechner Jan 23 '16 at 15:21

4 Answers4

32

Here is how I solved a similar problem.

First duplicate the image that you want to use as an image map and colour each section. Needless to say, a different colour for each section :D. Then create two ImageViews in your layout. Set the background of the first one as the image that you want displayed to screen and the background of the second as the coloured in one.

Then set the visibility of the second ImageView to invisible. If you run the program at this point you should see the image that you want displayed. Then use an OnTouch listener and get the colour of the pixel where you touched. The colour will correspond to that of the coloured image.

The following getColour method would need to be passed the x and y coordinates of the touch event. R.id.img2 is the invisible image.

private int getColour( int x, int y)
{
    ImageView img = (ImageView) findViewById(R.id.img2);
    img.setDrawingCacheEnabled(true); 
    Bitmap hotspots=Bitmap.createBitmap(img.getDrawingCache()); 
    img.setDrawingCacheEnabled(false);
    return hotspots.getPixel(x, y);
}

Hope this was of some help to you :).

Scotty
  • 336
  • 4
  • 4
  • do you know of any tutorial which has this method implemented, or some sample code available? – Kgrover Jul 20 '11 at 05:15
  • Won't work with Config.RGB_565, worked with: Bitmap.Config.ARGB_8888 – Guy Nov 08 '11 at 09:15
  • 1
    @scotty how did you came to know which hot spot is touched if there are many of hot spots are in image. – Deepika Lalra Aug 26 '13 at 04:31
  • 1
    There is a nice [tutorial](https://blahti.wordpress.com/2012/06/26/images-with-clickable-areas/) explaining this step by step. I hope it would be useful for somebody. – Mr.Moustard Nov 17 '14 at 14:29
2

I have not tried it, but this looks very promising.

I am about to try it in my project, I hope it works for you guys.

This guy is basically trying to emulate HTML Tag Map in droid with pinch zoom and drag.

AlexIIP
  • 2,461
  • 5
  • 29
  • 44
2

I did it with a mask like Scotty indicated, but I ran into more problems. Basically the colors returned by getPixel were slightly different than in the mask file. What I did was to load the mask in memory with scaling disabled and with full color options like this:

BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();
bitmapOptions.inTargetDensity = 1;
bitmapOptions.inDensity = 1;
bitmapOptions.inDither = false;
bitmapOptions.inScaled = false;
bitmapOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;
mask = BitmapFactory.decodeResource(appContext.getResources(), resMask, bitmapOptions);

Then I looked up the coords from the scaled image like this:

ImageView map = (ImageView) findViewById(R.id.image);
Drawable drawable = map.getDrawable();
Rect imageBounds = drawable.getBounds();
int scaledHeight = imageBounds.height();
int scaledWidth = imageBounds.width();
int scaledImageOffsetX = Math.round(event.getX()) - imageBounds.left;
int scaledImageOffsetY = Math.round(event.getY()) - imageBounds.top;

int origX = (scaledImageOffsetX * mask.getWidth() / scaledWidth);
int origY = (scaledImageOffsetY * mask.getHeight() / scaledHeight);

if(origX < 0) origX = 0;
if(origY < 0) origY = 0;
if(origX > mask.getWidth()) origX = mask.getWidth();
if(origY > mask.getHeight()) origY = mask.getHeight();

and then I applied mask.getPixel(origX, origY). It only works when the image is scaled with android:scaleType="fitXY" inside the ImageView otherwise the coords are off.

1

I followed clausundercover's answer but still had problems with the consistency of the pixel color over a region. What finally worked for me is to make sure that I use a PNG image with indexed color for the mask. In my case I used the web optimized palette (216 colors) and made sure that any colors I picked were values from that palette. Once I made this change, I got the same color value over the entire region.

museofwater
  • 409
  • 5
  • 9