The source code is available at the end of this tutorial
For this Android tutorial, I will show how to create an ImageView which is capable of rotating, pinch zoom in and out and move around on Touch Listener on android devices.
Here’s a quick and easy guide of Android’s multi-touch feature, i.e., one finger to move, two fingers to pinch zoom in and out and two or three fingers to rotate the ImageView.
Some basics of 2D Matrix transformations knowledge are a requirement for this tutorial. We will use Matrix class to map our points to new points.
When using Image viewer applications, they usually provide features of image processing, that is, pinch zoom in and zoom out, rotate or drag an image, etc. This guide takes you through how you can simply implement those features in a few lines of code in Android programmatically.
Note: we will use very few libraries to achieve the same, that is, only for the matrix libraries thus we will use our default Gradle properties configurations unlike other blog posts
First, we need to create our project and then add the java code below to your MainActivity.java and the XML to your activity_main.XML
The entire java code
MainActivity.java
package com.whatsonline.androidmultitouch;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.ImageView;
public class MainActivity extends Activity implements OnTouchListener {
// these matrices will be used to move and zoom image
private Matrix matrix = new Matrix();
private Matrix savedMatrix = new Matrix();
// we can be in one of these 3 states
private static final int NONE = 0;
private static final int DRAG = 1;
private static final int ZOOM = 2;
private int mode = NONE;
// remember some things for zooming
private PointF start = new PointF();
private PointF mid = new PointF();
private float oldDist = 1f;
private float d = 0f;
private float newRot = 0f;
private float[] lastEvent = null;
private ImageView view, fin;
private Bitmap bmap;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
view = (ImageView) findViewById(R.id.imageView);
fin = (ImageView) findViewById(R.id.imageView1);
view.setOnTouchListener(this);
}
public boolean onTouch(View v, MotionEvent event) {
// handle touch events here
view = (ImageView) v;
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
savedMatrix.set(matrix);
start.set(event.getX(), event.getY());
mode = DRAG;
lastEvent = null;
break;
case MotionEvent.ACTION_POINTER_DOWN:
oldDist = spacing(event);
if (oldDist > 10f) {
savedMatrix.set(matrix);
midPoint(mid, event);
mode = ZOOM;
}
lastEvent = new float[4];
lastEvent[0] = event.getX(0);
lastEvent[1] = event.getX(1);
lastEvent[2] = event.getY(0);
lastEvent[3] = event.getY(1);
d = rotation(event);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
lastEvent = null;
break;
case MotionEvent.ACTION_MOVE:
if (mode == DRAG) {
matrix.set(savedMatrix);
float dx = event.getX() - start.x;
float dy = event.getY() - start.y;
matrix.postTranslate(dx, dy);
} else if (mode == ZOOM) {
float newDist = spacing(event);
if (newDist > 10f) {
matrix.set(savedMatrix);
float scale = (newDist / oldDist);
matrix.postScale(scale, scale, mid.x, mid.y);
}
if (lastEvent != null && event.getPointerCount() == 2 || event.getPointerCount() == 3) {
newRot = rotation(event);
float r = newRot - d;
float[] values = new float[9];
matrix.getValues(values);
float tx = values[2];
float ty = values[5];
float sx = values[0];
float xc = (view.getWidth() / 2) * sx;
float yc = (view.getHeight() / 2) * sx;
matrix.postRotate(r, tx + xc, ty + yc);
}
}
break;
}
view.setImageMatrix(matrix);
bmap= Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.RGB_565);
Canvas canvas = new Canvas(bmap);
view.draw(canvas);
//fin.setImageBitmap(bmap);
return true;
}
public void ButtonClick(View v){
fin.setImageBitmap(bmap);
}
/**
* Determine the space between the first two fingers
*/
private float spacing(MotionEvent event) {
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
float s=x * x + y * y;
return (float)Math.sqrt(s);
}
/**
* Calculate the mid point of the first two fingers
*/
private void midPoint(PointF point, MotionEvent event) {
float x = event.getX(0) + event.getX(1);
float y = event.getY(0) + event.getY(1);
point.set(x / 2, y / 2);
}
/**
* Calculate the degree to be rotated by.
*
* @param event
* @return Degrees
*/
private float rotation(MotionEvent event) {
double delta_x = (event.getX(0) - event.getX(1));
double delta_y = (event.getY(0) - event.getY(1));
double radians = Math.atan2(delta_y, delta_x);
return (float) Math.toDegrees(radians);
}
}
For the Java code, we have added a touch event to our first ImageView to perform all the transformations as shown above. On button click action, set our mapped ImageView to our second ImageView.
The entire XML code
activity_main.XML
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
xmlns:android="http://schemas.android.com/apk/res/android" >
<FrameLayout
android:layout_width="fill_parent"
android:id="@+id/frm"
android:layout_height="250dp">
<ImageView android:id="@+id/imageView"
android:layout_width="fill_parent"
android:layout_height="250dp"
android:src="@drawable/cat"
android:scaleType="matrix" />
</FrameLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_below="@+id/frm"
android:layout_height="match_parent">
<Button
android:layout_width="wrap_content"
android:text="Finalise"
android:onClick="ButtonClick"
android:layout_height="wrap_content" />
<ImageView android:id="@+id/imageView1"
android:layout_width="fill_parent"
android:layout_height="250dp"
android:src="@drawable/cat"
/>
</LinearLayout>
</RelativeLayout>
For our XML file, we have created two ImageViews and a button widget. The first ImageView will perform the transformations (rotate, zoom, drag). On button click, our transformed imageView will be set to the second ImageView as Bitmap Image as explained in the Java code below.
public void ButtonClick(View v){
fin.setImageBitmap(bmap);
}
The code example below shows how to get a bitmap Image from the transformed ImageView.
bmap= Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.RGB_565);
Canvas canvas = new Canvas(bmap);
view.draw(canvas);
Finally, we are done, you can download the code below for a quicker implementation and subscribe to our newsletter to get more of our tutorials direct to your mailbox.
Comments
Post a Comment