1 . Android Images with Clickable Areas - Part 1 by Bill Lahti
2 . Java Pan / Zoom listener for Android by John Stewien
From first article you can learn how to make an image with clickable areas very easily and from the second article you can learn how to get the pan/zoom effect to an image.
I just combined these two ideas and created an application which has both features. (Image with clickable and at the same time it can be zoomed as well)
I am going to explain only the changes I did for those codes. I mention the name of the java file with codes for your easy reference.You can find the link to source code at the bottom of this article.
PanAndZoomListener class declaration : PanAndZoomListener extends View.OnTouchListener
(1) Since Images with Clickable areas have two images and we need to zoom both images at the same time I passed both ImageViews as a View array to PanAndZoomListener constructor. Also we need to pass the Context of the Activity class as well. Here is the code,
Inside PanAndZoomListener.java
public PanAndZoomListener(FrameLayout containter, View[] views, int anchor,Context c) {
panZoomCalculator = new PanZoomCalculator(containter, views, anchor);
//iv_front and iv_back are ImageViews declared as instance variables.
iv_front = (ImageView) views[0];
iv_back = (ImageView)views[1];
context = c;
iv_front.setOnTouchListener(this);
}
(2) Now we need to change the panZoomCalculator constructor accordingly. Because earlier it accepted one View. But now we are passing a View array. So lets change it like this,
Inside PanAndZoomListener.java
PanZoomCalculator(View container, View[] child, int anchor) {
// Initialize class fields
currentPan = new PointF(0, 0);
currentZoom = 1f;
this.window = container;
this.child1 = child[0];
this.child2 = child[1];
matrix = new Matrix();
this.anchor = anchor;
onPanZoomChanged();
this.child1.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
onPanZoomChanged();
}
});
this.child2.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
onPanZoomChanged();
}
});
}
(3) Then modify onPanZoomChanged() method like this,
you need to create another if-else block for child2
Inside PanAndZoomListener.java
if (child1 instanceof ImageView && ((ImageView) child1).getScaleType() == ImageView.ScaleType.MATRIX) {
(3) Then modify onPanZoomChanged() method like this,
you need to create another if-else block for child2
Inside PanAndZoomListener.java
if (child1 instanceof ImageView && ((ImageView) child1).getScaleType() == ImageView.ScaleType.MATRIX) {
ImageView view = (ImageView) child1;
Drawable drawable = view.getDrawable();
if (drawable != null) {
Bitmap bm = ((BitmapDrawable) drawable).getBitmap();
if (bm != null) {
float bmWidth = bm.getWidth();
float bmHeight = bm.getHeight();
float fitToWindow = Math.min(winWidth / bmWidth, winHeight / bmHeight);
float xOffset = (winWidth - bmWidth * fitToWindow) * 0.5f * currentZoom;
float yOffset = (winHeight - bmHeight * fitToWindow) * 0.5f * currentZoom;
matrix.reset();
matrix.postScale(currentZoom * fitToWindow, currentZoom * fitToWindow);
matrix.postTranslate(currentPan.x + xOffset, currentPan.y + yOffset);
((ImageView) child1).setImageMatrix(matrix);
}
}
}else {
ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams)child1.getLayoutParams();
lp.leftMargin = (int) currentPan.x + panJitter;
lp.topMargin = (int) currentPan.y;
lp.width = (int) (window.getWidth() * currentZoom);
lp.height = (int) (window.getHeight() * currentZoom);
panJitter ^= 1;
child1.setLayoutParams(lp);
}
(4) Inside onTouch() we need to add the code for what to happen when a user is pressed a particular area on the image. It should be triggered when MotionEvent.ACTION_UP event has occurred.
Inside PanAndZoomListener.java
case MotionEvent.ACTION_UP: {
if (view.getId() == iv_front.getId()) {
final int x = (int) event.getX();
final int y = (int) event.getY();
int touch_color = getHotspotColor(x, y);
int tolerance = 25;
if (closeMatch(Color.BLUE, touch_color, tolerance))
Toast.makeText(context, "Pressed Blue color box", Toast.LENGTH_SHORT).show();
else if (closeMatch(Color.RED, touch_color, tolerance))
Toast.makeText(context, "Pressed Red color box", Toast.LENGTH_SHORT).show();
else if (closeMatch(Color.GREEN, touch_color, tolerance))
Toast.makeText(context, "Pressed Green color box", Toast.LENGTH_SHORT).show();
else if (closeMatch(Color.YELLOW, touch_color, tolerance))
Toast.makeText(context, "Pressed Yellow color box", Toast.LENGTH_SHORT).show();
}
}
(5) Now inside our onCreate() of the Activity class, we need to initialize the views and make a new PanAndZoomListener object and pass the values like this,
Inside MainActivity.java
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FrameLayout fl = (FrameLayout)findViewById(R.id.frame_layout);
iv_front = (ImageView)findViewById(R.id.pan_and_zoom_image);
iv_back = (ImageView)findViewById(R.id.pan_and_zoom_image_areas);
View[] views = {iv_front,iv_back};
fl.setOnTouchListener(new PanAndZoomListener(fl, views, PanAndZoomListener.Anchor.TOPLEFT,MainActivity.this));
}
That is it.
Here is the source code (I used Android Studio, min sdk =11)
In my source code I used the below image. When you pressed the tables at right side toast messages will be appeared accordingly.