How to rotate the Canvas on fix angle or item - java

This is my code to rotate the wheel and sound cordinator according to rotation but I want to rotate the wheel according to fix color on fix point.
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Rect;
import android.graphics.RectF;
import android.media.MediaPlayer;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import com.spin.wheel.manager.MyDBAdapter;
import com.spin.wheel.manager.Prefs;
import com.spin.wheel.ui.activity.HomeActivity;
import java.util.List;
import java.util.Random;
public class WheelView extends View {
public boolean lifted;
private Paint circlePaint;
private long currTime;
private String item;
private Paint item10Paint;
private Paint item11Paint;
private Paint item12Paint;
private Paint item13Paint;
private Paint item14Paint;
private Paint item15Paint;
private Paint item1Paint;
private Paint item2Paint;
private Paint item3Paint;
private Paint item4Paint;
private Paint item5Paint;
private Paint item6Paint;
private Paint item7Paint;
private Paint item8Paint;
private Paint item9Paint;
private float itemLength;
private List<String> itemNames;
private double lastTheta;
private String listName;
private Paint markerPaint;
private long oldTime;
private Paint pointerPaint;
private int px;
WheelView wheelView;
private int py;
private float radius;
private MediaPlayer resourcePlayer;
private Paint rimPaint;
private double rotationOffset;
private int selected;
private Paint textPaint;
private boolean textSet;
private long timeDiff;
private Paint titlePaint;
private String winner;
int padding;
int center;
Context mContext;
public WheelView(Context context) {
super(context);
mContext=context;
initWheelView();
}
public WheelView(Context context, AttributeSet attrs) {
super(context, attrs);
mContext=context;
initWheelView();
}
public WheelView(Context context, AttributeSet ats, int defaultStyle) {
super(context, ats, defaultStyle);
mContext=context;
initWheelView();
}
protected void initWheelView() {
setFocusable(true);
Resources r = getResources();
this.circlePaint = new Paint(1);
this.circlePaint.setColor(r.getColor(R.color.wheel_color));
this.circlePaint.setStrokeWidth(5.0f);
this.circlePaint.setStyle(Style.STROKE);
this.rimPaint = new Paint(1);
this.rimPaint.setColor(r.getColor(R.color.text_color));
this.rimPaint.setStrokeWidth(1.0f);
this.rimPaint.setStyle(Style.STROKE);
this.textPaint = new Paint(1);
this.textPaint.setColor(r.getColor(R.color.text_color));
this.titlePaint = new Paint(1);
this.titlePaint.setColor(r.getColor(R.color.text_color));
this.pointerPaint = new Paint(1);
this.pointerPaint.setColor(r.getColor(R.color.pointer_color));
this.markerPaint = new Paint(1);
this.markerPaint.setStrokeWidth(2.0f);
this.markerPaint.setColor(r.getColor(R.color.marker_color));
this.item1Paint = new Paint(1);
this.item1Paint.setColor(r.getColor(R.color.item1_color));
this.item2Paint = new Paint(1);
this.item2Paint.setColor(r.getColor(R.color.item2_color));
this.item3Paint = new Paint(1);
this.item3Paint.setColor(r.getColor(R.color.item3_color));
this.item4Paint = new Paint(1);
this.item4Paint.setColor(r.getColor(R.color.item4_color));
this.item5Paint = new Paint(1);
this.item5Paint.setColor(r.getColor(R.color.item5_color));
this.item6Paint = new Paint(1);
this.item6Paint.setColor(r.getColor(R.color.item6_color));
this.item7Paint = new Paint(1);
this.item7Paint.setColor(r.getColor(R.color.item7_color));
this.item8Paint = new Paint(1);
this.item8Paint.setColor(r.getColor(R.color.item8_color));
this.item9Paint = new Paint(1);
this.item9Paint.setColor(r.getColor(R.color.item9_color));
this.item10Paint = new Paint(1);
this.item10Paint.setColor(r.getColor(R.color.item10_color));
this.item11Paint = new Paint(1);
this.item11Paint.setColor(r.getColor(R.color.item11_color));
this.item12Paint = new Paint(1);
this.item12Paint.setColor(r.getColor(R.color.item12_color));
this.item13Paint = new Paint(1);
this.item13Paint.setColor(r.getColor(R.color.item13_color));
this.item14Paint = new Paint(1);
this.item14Paint.setColor(r.getColor(R.color.item14_color));
this.item15Paint = new Paint(1);
this.item15Paint.setColor(r.getColor(R.color.item15_color));
this.lifted = false;
this.selected = -1;
this.lastTheta = 0.0d;
this.timeDiff = 0;
this.oldTime = System.currentTimeMillis();
this.currTime = System.currentTimeMillis();
this.winner = "";
this.resourcePlayer = MediaPlayer.create(getContext(), R.raw.wheel_sound_new);
this.item = "";
this.itemLength = 0.0f;
this.listName = "";
this.textSet = false;
}
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(measure(widthMeasureSpec), measure(heightMeasureSpec));
int width = Math.min(getMeasuredWidth(), getMeasuredHeight());
padding = getPaddingLeft() == 0 ? 0 : getPaddingLeft();
radius = width - padding * 2;
center = width / 2;
}
private int measure(int measureSpec) {
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == 0) {
return 200;
}
return specSize;
}
public boolean withinWheel(float _x, float _y) {
return getRadius() * getRadius() > ((_x - ((float) getPX())) * (_x - ((float) getPX()))) + ((((float) getPY()) - _y) * (((float) getPY()) - _y));
}
public void setList(String _listName) {
this.listName = _listName;
}
public void setRotation(double _rotation) {
Log.e("##_rotation", String.valueOf(_rotation));
this.rotationOffset = _rotation % 360.0d;
}
public double getRotationNumber() {
Log.e("##rotationOffset", String.valueOf(rotationOffset));
return this.rotationOffset;
}
public void setLastTheta(double _lastTheta, float width) {
float offset = 12800.0f / width;
if (_lastTheta < -40.0d) {
_lastTheta = (double) (-offset);
}
if (_lastTheta > 40.0d) {
_lastTheta = (double) offset;
}
this.lastTheta = _lastTheta;
}
public void setItems(List<String> items) {
this.itemNames = items;
}
public int getPX() {
return getMeasuredWidth() / 2;
}
public int getPY() {
return getMeasuredHeight() / 2;
}
public float getRadius() {
return ((float) Math.min(getPX(), getPY())) * 0.8f;
}
protected void onDraw(Canvas canvas) {
float tempAngle = 0;
float sweepAngle = 360 /6;
if (this.itemNames != null) {
int i;
float offSet = 0;
this.px = getMeasuredWidth() / 2;
this.py = getMeasuredHeight() / 2;
if (!this.textSet) {
this.textPaint.setTextSize((float) (getMeasuredWidth() / 25));
this.titlePaint.setTextSize((float) (getMeasuredWidth() / 15));
this.textSet = true;
}
this.radius = ((float) Math.min(this.px, this.py)) * 0.8f;
float incr = 360.0f / ((float) this.itemNames.size());
RectF myCircleBox = new RectF(((float) this.px) - this.radius, ((float) this.py) - this.radius, ((float) this.px) + this.radius, ((float) this.py) + this.radius);
RectF rectF = new RectF(((float) this.px) - (this.radius / 5.0f), ((float) this.py) - (this.radius * 1.1f), ((float) this.px) + (this.radius / 5.0f), ((float) this.py) - (this.radius * 0.6f));
rectF = new RectF((((float) this.px) - (this.radius / 5.0f)) + 5.0f, (((float) this.py) - (this.radius * 1.1f)) + 2.0f, (((float) this.px) + (this.radius / 5.0f)) - 5.0f, (((float) this.py) - (this.radius * 0.6f)) - 12.0f);
Log.e("##rotationOffset", String.valueOf(rotationOffset));
double actualRotation = this.rotationOffset + ((double) ((incr / 2.0f) + 90.0f));
canvas.save();
canvas.rotate((float) this.rotationOffset, (float) this.px, (float) this.py);
for (i = 0; i < this.itemNames.size(); i++) {
Paint itemPaint;
switch (i) {
case MyDBAdapter.KEY_ID_COLUMN /*0*/:
itemPaint = this.item1Paint;
break;
case MyDBAdapter.NAME_COLUMN /*1*/:
itemPaint = this.item2Paint;
break;
case MyDBAdapter.NAME_REF /*2*/:
itemPaint = this.item3Paint;
break;
case 3:
itemPaint = this.item4Paint;
break;
case 4:
itemPaint = this.item5Paint;
break;
case 5:
itemPaint = this.item6Paint;
break;
case 6:
itemPaint = this.item7Paint;
break;
case 7:
itemPaint = this.item8Paint;
break;
case 8:
itemPaint = this.item9Paint;
break;
case 9:
itemPaint = this.item10Paint;
break;
case 10:
itemPaint = this.item11Paint;
break;
case 11:
itemPaint = this.item12Paint;
break;
case 12:
itemPaint = this.item13Paint;
break;
case 13:
itemPaint = this.item14Paint;
break;
case 14:
itemPaint = this.item15Paint;
break;
default:
itemPaint = this.item1Paint;
break;
}
offSet = ((float) i) * (-incr);
canvas.save();
canvas.rotate(offSet, (float) this.px, (float) this.py);
canvas.drawArc(myCircleBox, (-incr) / 2.0f, incr, true, itemPaint);
this.item = ((String) this.itemNames.get(i)).toString();
this.itemLength = (float) ((int) this.textPaint.measureText(this.item));
if (((double) this.itemLength) > ((double) this.radius) * 0.8d) {
this.item = this.item.substring(0, (int) (((double) this.item.length()) * ((((double) this.radius) * 0.8d) / ((double) ((int) this.textPaint.measureText(this.item))))));
this.itemLength = (float) ((int) this.textPaint.measureText(this.item));
}
// canvas.drawText(this.item, (((float) this.px) + (this.radius / 2.0f)) - (this.itemLength / 2.0f), (float) (this.py + ((int) (((double) this.textPaint.measureText("yY")) / 2.5d))), this.textPaint);
Bitmap icon = BitmapFactory.decodeResource(getResources(),R.drawable.ic_laun);
//drawImage(canvas, tempAngle,icon );
tempAngle += sweepAngle;
canvas.restore();
}
for (i = 0; i < this.itemNames.size(); i++) {
offSet = ((float) i) * incr;
canvas.save();
canvas.rotate(offSet, (float) this.px, (float) this.py);
canvas.save();
canvas.rotate(incr / 2.0f, (float) this.px, (float) this.py);
canvas.drawLine(((float) this.px) + this.radius, (float) this.py, (float) this.px, (float) this.py, this.markerPaint);
Bitmap icon =
BitmapFactory.decodeResource(getResources(),R.drawable.ic_laun);
drawImage(canvas, tempAngle,icon );
canvas.restore();
canvas.restore();
}
canvas.restore();
canvas.drawCircle((float) this.px, (float) this.py, this.radius, this.circlePaint);
canvas.drawCircle((float) this.px, (float) this.py, this.radius + (this.circlePaint.getStrokeWidth() * 0.5f), this.rimPaint);
canvas.drawCircle((float) this.px, (float) this.py, 2.0f, this.rimPaint);
canvas.drawCircle((float) this.px, (float) this.py, 1.0f, this.rimPaint);
canvas.drawArc(rectF, 250.0f, 40.0f, true, this.textPaint);
canvas.drawArc(rectF, 250.0f, 40.0f, true, this.pointerPaint);
if (actualRotation < 0.0d) {
actualRotation += 360.0d;
} else if (actualRotation > 360.0d) {
actualRotation -= 360.0d;
}
if (!(this.selected == -1 || this.selected == ((int) (actualRotation / ((double) incr))) || !Prefs.getMusic(getContext()) || this.resourcePlayer == null)) {
if (this.resourcePlayer.isPlaying()) {
this.resourcePlayer.seekTo(0);
} else {
this.resourcePlayer.start();
}
}
this.selected = (int) (actualRotation / ((double) incr));
if (this.lifted) {
this.winner = ((String) this.itemNames.get(this.selected)).toString();
}
canvas.drawText(this.winner, (float) (this.px - (((int) this.titlePaint.measureText(this.winner)) / 2)), (((float) this.py) + this.radius) + ((float) (getMeasuredWidth() / 10)), this.titlePaint);
canvas.drawText(this.listName, (float) (this.px - (((int) this.titlePaint.measureText(this.listName)) / 2)), (((float) this.py) - this.radius) - ((float) (getMeasuredWidth() / 18)), this.titlePaint);
if (this.lifted) {
long currentTimeMillis;
if (this.lastTheta > 0.0d) {
currentTimeMillis = System.currentTimeMillis();
this.currTime = currentTimeMillis;
this.timeDiff = currentTimeMillis - this.oldTime;
this.oldTime = this.currTime;
setRotation(getRotationNumber() + this.lastTheta);
this.lastTheta -= (double) (0.002f * ((float) this.timeDiff));
if (this.lastTheta <= 0.0d) {
this.lifted = false;
Log.e("#finalDone","finalDone"+getRotationNumber());
Log.e("#offset","finalDone"+offSet);
Intent intent=new Intent(mContext, HomeActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK|Intent.FLAG_ACTIVITY_CLEAR_TOP);
mContext.startActivity(intent);
}
} else {
currentTimeMillis = System.currentTimeMillis();
this.currTime = currentTimeMillis;
this.timeDiff = currentTimeMillis - this.oldTime;
this.oldTime = this.currTime;
setRotation(getRotationNumber() + this.lastTheta);
this.lastTheta += (double) (0.002f * ((float) this.timeDiff));
if (this.lastTheta >= 0.0d) {
this.lifted = false;
Log.e("#finalDone","finalDone"+getRotationNumber());
Intent intent=new Intent(mContext, HomeActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK|Intent.FLAG_ACTIVITY_CLEAR_TOP);
mContext.startActivity(intent);
}
}
invalidate();
}
}
}
private void drawImage(Canvas canvas, float tempAngle, Bitmap bitmap) {
//get every arc img width and angle
int mWheelItemssize=6;
int imgWidth = (int)radius / 6;
float angle = (float) ((tempAngle + 360 / mWheelItemssize / 2) * Math.PI / 180);
//calculate x and y
int x = (int) (center + (int)radius / 2 / 2 * Math.cos(angle));
int y = (int) (center + (int) radius / 2 / 2 * Math.sin(angle));
Rect rect = new Rect(x - imgWidth /2, y - imgWidth / 2, x + imgWidth / 2, y + imgWidth / 2);
Bitmap rotatedBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), null, true);
canvas.drawBitmap(bitmap, null, rect, null);
}
private void drawImage1(Canvas canvas, float tmpAngle, Bitmap bitmap) {
int imgWidth = (int) (radius / itemNames.size());
float angle = (float) ((tmpAngle + 360 / itemNames.size() / 2) * Math.PI / 180);
int x = (int) (center + radius / 2 / 2 * Math.cos(angle));
int y = (int) (center + radius / 2 / 2 * Math.sin(angle));
Rect rect = new Rect(x - imgWidth/2, y - imgWidth/2, x + imgWidth/2, y + imgWidth/2);
canvas.drawBitmap(bitmap, null, rect, null);
}
void OnDestroy() {
if (this.resourcePlayer != null) {
this.resourcePlayer.release();
}
}
public void autoSpin(float seed) {
if (seed >= 20.0f) {
seed = 15.0f;
}
seed = 8.0f;
this.oldTime = System.currentTimeMillis();
this.currTime = System.currentTimeMillis();
Log.e("##oldTime", String.valueOf(System.currentTimeMillis()));
Log.e("##Random", String.valueOf((new Random().nextFloat())));
Log.e("##Random", String.valueOf((new Random().nextFloat())));
int randomno=3;
this.lastTheta = (double) ((randomno * seed));
Log.e("##lastTheta", String.valueOf(lastTheta));
this.lifted = true;
invalidate();
}
}
HomeActivity
#Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.autoSpinButton:
// wheelView.rotateWheelTo(wheelView,3);
autoSpinButton.setEnabled(false);
Log.e("###Seed", String.valueOf(20.0f * (320.0f / width)));
wheelView.autoSpin(5.0);
break;
}
}
main Layout
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.spin.wheel.widgets.WheelView
android:id="#+id/wheelView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/backrepeat"/>
<Button
android:id="#+id/autoSpinButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"
android:layout_centerInParent="true"
android:text="SPIN" />
</RelativeLayout>
Please Help

Related

Placing objects on Face based on landmark positions google vision api

I am trying to detect eyes and put glasses over eyes using Google Mobile Vision api.
here is what i have tried
Face face = faces.valueAt(0);
Landmark leftEye = null;
Landmark rightEye = null;
for (Landmark landmark : face.getLandmarks())
{
if (landmark.getType() == Landmark.LEFT_EYE)
leftEye = landmark;
else if (landmark.getType() == Landmark.RIGHT_EYE)
rightEye = landmark;
}
if(leftEye != null && rightEye != null)
{
double diff = leftEye.getPosition().x * mImageView.scale - rightEye.getPosition().x * mImageView.scale - 15;
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.raw.glasses1);
int width = (int) pxFromDp(this, (float) diff);
final double viewWidthToBitmapWidthRatio = (double)width / (double) bitmap.getWidth();
int height = (int) (bitmap.getHeight() * viewWidthToBitmapWidthRatio);
filterImg.getLayoutParams().width = width;
filterImg.getLayoutParams().height = height;
filterImg.invalidate();
float x = (rightEye.getPosition().x + 15) * mImageView.scale;
float y = (rightEye.getPosition().y + face.getPosition().y) * mImageView.scale;
filterImg.setX(x);
filterImg.setY(y);
filterImg.setRotation(face.getEulerY());
filterImg.setImageResource(rawFile);
mImageView.setData(bitmap, faces);
}
else
Toast.makeText(ImageFiltersActivity.this, "Unable to parse landmarks", Toast.LENGTH_SHORT).show();
This is my code copied from google sources
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (mBitmap != null && mFaces != null) {
double deviceScale = drawBitmapToDeviceSize(canvas);
drawFaceDetectionBox(canvas, deviceScale);
}
}
private double drawBitmapToDeviceSize(Canvas canvas) {
double viewWidth = canvas.getWidth();
double viewHeight = canvas.getHeight();
double imageWidth = mBitmap.getWidth();
double imageHeight = mBitmap.getHeight();
scale = (float) Math.min(viewWidth / imageWidth, viewHeight / imageHeight);
Rect bitmapBounds = new Rect(0, 0, (int) (imageWidth * scale), (int) (imageHeight * scale));
return scale;
}
private void drawFaceDetectionBox(Canvas canvas, double deviceScale)
{
Paint paint = new Paint();
paint.setColor(Color.YELLOW);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(3);
for (int i = 0; i < mFaces.size(); ++i)
{
Face face = mFaces.valueAt(i);
float x1 = (float) (face.getPosition().x * deviceScale);
float y1 = (float) (face.getPosition().y * deviceScale);
float x2 = (float) (x1 + face.getWidth() * deviceScale);
float y2 = (float) (y1 + face.getHeight() * deviceScale);
for (Landmark landmark : face.getLandmarks())
{
int type = landmark.getType();
float m1 = (float) (landmark.getPosition().x * deviceScale);
float m2 = (float) (landmark.getPosition().y * deviceScale);
canvas.drawCircle(m1, m2, 2, paint);
}
canvas.drawRect(x1, y1, x2, y2,
paint);
}
}
Result is
float m1 = (float) (landmark.getPosition().x * deviceScale);
float m2 = (float) (landmark.getPosition().y * deviceScale);
canvas.drawCircle(m1, m2, 2, paint);
works fine but when i move my imageView
float x = (rightEye.getPosition().x + 15) * mImageView.scale;
float y = (rightEye.getPosition().y + face.getPosition().y) * mImageView.scale;
filterImg.setX(x);
filterImg.setY(y);
the imageview is misplaced and is NOT on eyes.
Anyone can explain or help what am i missing?
double diff = leftEye.getPosition().x * mImageView.scale - rightEye.getPosition().x * mImageView.scale - 15;
remove -15 and try again.

How to draw new circle on touch and remove previous circle

I can create circle on touch but can not remove the previous one. I have manage to remove the very first circle but the code is poor and it does not really work as I want. I like to draw circle every time I touch the screen and remove the previous circle . So the screen starts with a circle and as I will touch a new position the previous should be removed and there will be a new one.So how to do that part?
Here is my work:
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
Display display = new Display(this);
display.init();
display.backPaint.setColor(Color.WHITE);
setContentView(display);
}
static class Display extends View {
ArrayList<Point> points = new ArrayList();
int touch1_x=700;
int touch1_y=700;
Paint backPaint;
Paint circlePaint;
Paint circlePaint2;
Display(Context context) {
super(context);
}
void init() {
backPaint = new Paint();
backPaint.setColor(Color.WHITE);
backPaint.setStyle(Paint.Style.FILL);
circlePaint = new Paint();
circlePaint.setColor(Color.YELLOW);
circlePaint2 = new Paint();
circlePaint2.setColor(Color.WHITE);
setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (MotionEvent.ACTION_DOWN == event.getActionMasked()) {
// if (event.getX(event.getActionIndex()) > 100 && event.getX(event.getActionIndex()) < 200) {
touch1_x = (int) event.getX(event.getActionIndex());
touch1_y = (int) event.getY(event.getActionIndex());
// }
System.out.println("touch1_x ===" + touch1_x);
points.add(new Point(touch1_x, touch1_y));
points.add(new Point(touch1_x, touch1_y));
return true;
}
return false;
}
});
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawRect(0, 0, getWidth(), getHeight(), backPaint);
canvas.drawCircle(touch1_x, touch1_y, 50, circlePaint);
for(Point p: points){
canvas.drawCircle(p.x, p.y, 50, circlePaint);
}
for(Point p: points){
canvas.drawCircle(p.x, p.y, 50,circlePaint2 );
}
invalidate();
}
}
}
relevant question
You could erase canvas before drawing the next circle, using
canvas.drawColor(Color.TRANSPARENT,Mode.CLEAR);
import turtle
t=turtle.Turtle()
wn=turtle.Screen()
for count in range(360):
t.fd(3)
t.rt(1)
wn.exitonclick()
I have a customised view for photo annotate, you can use this to do your job.
1: Create a file AnnotationView.java and copy the following code
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.ImageView;
/**
* #author Bob Gao
* http://bobgao.net
*/
public class AnnotationView extends ImageView implements OnTouchListener {
private static final float KEY_STROKE_WIDTH = 4;
private List<Annotation> annotations = new ArrayList<Annotation>();
private Annotation mAnnotation;
private Canvas mCanvas;
private Paint mPaint;
// private Rect mOutRect;
public AnnotationView(Context context) {
super(context);
setOnTouchListener(this);
setDrawingCacheEnabled(true);
setScaleType(ScaleType.FIT_XY);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
this.mCanvas = canvas;
for (Annotation annotation : annotations) {
mPaint.setColor(annotation.getColor());
switch (annotation.getShape()) {
case Annotation.KEY_SHAPE_CIRCLE:
drawCircle(annotation.getX(), annotation.getY(), annotation.getRadius());
break;
case Annotation.KEY_SHAPE_ARROW:
drawAL((int) annotation.getX(), (int) annotation.getY(), (int) annotation.getRadius(), annotation.getDegree());
break;
case Annotation.KEY_SHAPE_SQUARES:
drawRect((int) annotation.getX(), (int) annotation.getY(), (int) annotation.getRadius());
break;
case Annotation.KEY_SHAPE_TRIANGLE:
drawTriangle((int) annotation.getX(), (int) annotation.getY(), (int) annotation.getRadius(), annotation.getDegree());
break;
}
}
}
/**
* Draw a triangle
*
* #param x
* #param y
* #param r
*/
public void drawTriangle(int x, int y, int r, float degree) {
Path path = new Path();
path.moveTo(x, y);
path.lineTo(x - 2 * r, y + 2 * r);
path.lineTo(x + 2 * r, y + 2 * r);
path.lineTo(x, y);
path.close();
rotatePath(path, degree);
mCanvas.drawPath(path, mPaint);
}
public void drawRect(int x, int y, int r) {
int lenght = 4 * r;
int left = x - lenght / 2;
int top = y - lenght / 2;
int right = x + lenght / 2;
int bottom = y + lenght / 2;
Path path = new Path();
path.moveTo(left, top);
path.lineTo(right, top);
path.lineTo(right, bottom);
path.lineTo(left, bottom);
path.lineTo(left, top);
path.close();
mCanvas.drawPath(path, mPaint);
}
public void drawCircle(float x, float y, float r) {
mCanvas.drawCircle(x, y, r, mPaint);
}
/**
* Draw arrow
*
* #param sx
* #param sy
* #param ex
* #param ey
*/
public void drawAL(int sx, int sy, int r, float degree) {
int ex = (int) (sx + 2 * r);
int ey = (int) (sy + 2 * r);
switch (new Float(degree).intValue()) {
case 90:
ex = (int) (sx - 2 * r);
ey = (int) (sy + 2 * r);
break;
case 180:
ex = (int) (sx - 2 * r);
ey = (int) (sy - 2 * r);
break;
case 270:
ex = (int) (sx + 2 * r);
ey = (int) (sy - 2 * r);
break;
}
double H = 8; // the height of arrow
double L = 3.5; // half of bottom line
int x3 = 0;
int y3 = 0;
int x4 = 0;
int y4 = 0;
double awrad = Math.atan(L / H); // the rotation of arrow
double arraow_len = Math.sqrt(L * L + H * H); // the length of arrow
double[] arrXY_1 = rotateVec(ex - sx, ey - sy, awrad, true, arraow_len);
double[] arrXY_2 = rotateVec(ex - sx, ey - sy, -awrad, true, arraow_len);
double x_3 = ex - arrXY_1[0]; // (x3,y3) the first point
double y_3 = ey - arrXY_1[1];
double x_4 = ex - arrXY_2[0]; // (x4,y4) the second point
double y_4 = ey - arrXY_2[1];
Double X3 = new Double(x_3);
x3 = X3.intValue();
Double Y3 = new Double(y_3);
y3 = Y3.intValue();
Double X4 = new Double(x_4);
x4 = X4.intValue();
Double Y4 = new Double(y_4);
y4 = Y4.intValue();
// draw line
mCanvas.drawLine(sx, sy, ex, ey, mPaint);
Path triangle = new Path();
triangle.moveTo(ex, ey);
triangle.lineTo(x3, y3);
triangle.lineTo(x4, y4);
triangle.close();
mCanvas.drawPath(triangle, mPaint);
}
// Calculate
public double[] rotateVec(int px, int py, double ang, boolean isChLen, double newLen) {
double mathstr[] = new double[2];
// 矢量旋转函数,参数含义分别是x分量、y分量、旋转角、是否改变长度、新长度
double vx = px * Math.cos(ang) - py * Math.sin(ang);
double vy = px * Math.sin(ang) + py * Math.cos(ang);
if (isChLen) {
double d = Math.sqrt(vx * vx + vy * vy);
vx = vx / d * newLen;
vy = vy / d * newLen;
mathstr[0] = vx;
mathstr[1] = vy;
}
return mathstr;
}
#Override
public boolean onTouch(View v, MotionEvent event) {
float x = event.getX();
float y = event.getY();
if (mAnnotation != null) {
float minX = 0;
float minY = 0;
float maxX = 0;
float maxY = 0;
switch (mAnnotation.getShape()) {
case Annotation.KEY_SHAPE_ARROW:
minX = 0;
minY = 0;
maxX = getLeft() + getWidth() - mAnnotation.getRadius();
maxY = getTop() + getHeight() - mAnnotation.getRadius();
break;
case Annotation.KEY_SHAPE_SQUARES:
minX = getLeft() + mAnnotation.getRadius() / 2;
minY = getTop() + mAnnotation.getRadius() / 2;
maxX = getLeft() + getWidth() - mAnnotation.getRadius() / 2;
maxY = getTop() + getHeight() - mAnnotation.getRadius() / 2;
break;
case Annotation.KEY_SHAPE_CIRCLE:
minX = 0;
minY = 0;
maxX = getLeft() + getWidth() - mAnnotation.getRadius();
maxY = getTop() + getHeight() - mAnnotation.getRadius();
case Annotation.KEY_SHAPE_TRIANGLE:
minX = getLeft() + mAnnotation.getRadius();
minY = getTop() + mAnnotation.getRadius();
maxX = getLeft() + getWidth() - mAnnotation.getRadius();
maxY = getTop() + getHeight() - mAnnotation.getRadius();
break;
}
if (x > minX && x < maxX && y > minY && y < maxY) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mAnnotation.setX(x);
mAnnotation.setY(y);
postInvalidate();
case MotionEvent.ACTION_MOVE:
mAnnotation.setX(x);
mAnnotation.setY(y);
postInvalidate();
break;
}
}
return true;
}
return false;
}
public void startAnnotate(String pathName) {
mAnnotation = new Annotation();
mAnnotation.setMaxRadius(getWidth() / 2);
mAnnotation.setColor(Color.RED);
mAnnotation.setX(getWidth() / 2);
mAnnotation.setY(getHeight() / 2);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setColor(Color.RED);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(KEY_STROKE_WIDTH);
annotations.add(mAnnotation);
postInvalidate();
}
public void stopAnnotate() {
if (annotations.isEmpty()) {
mPaint = null;
mAnnotation = null;
} else {
annotations.remove(annotations.size() - 1);
if (annotations.isEmpty()) {
mAnnotation = null;
mPaint = null;
} else {
mAnnotation = annotations.get(annotations.size() - 1);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setColor(mAnnotation.getColor());
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(KEY_STROKE_WIDTH);
}
}
postInvalidate();
}
public void plus() {
if (mAnnotation != null) {
mAnnotation.plus();
postInvalidate();
}
}
public void sub() {
if (mAnnotation != null) {
mAnnotation.sub();
postInvalidate();
}
}
public void rotateRight() {
if (mAnnotation != null) {
if (mAnnotation.getDegree() >= 360) {
mAnnotation.setDegree(0);
} else {
mAnnotation.setDegree(mAnnotation.getDegree() + 90);
}
postInvalidate();
}
}
public void rotateLeft() {
if (mAnnotation != null) {
if (mAnnotation.getDegree() <= 0) {
mAnnotation.setDegree(270);
} else {
mAnnotation.setDegree(mAnnotation.getDegree() - 90);
}
postInvalidate();
}
}
public void changeColor(int color) {
if (mAnnotation != null) {
mAnnotation.setColor(color);
mPaint.setColor(color);
}
postInvalidate();
}
/**
* Change the shape
*
* #param id
*/
public void changeShape(int id) {
if (mAnnotation != null) {
mAnnotation.setShape(id);
postInvalidate();
}
}
/**
* Draw line
*
* #param fromX
* start point x
* #param fromY
* start point y
* #param toX
* end point x
* #param toY
* end point y
*/
public void drawLine(float fromX, float fromY, float toX, float toY) {
Path linePath = new Path();
linePath.moveTo(fromX, fromY);
linePath.lineTo(toX, toY);
linePath.close();
mCanvas.drawPath(linePath, mPaint);
invalidate();
}
public List<Annotation> getAnnotations() {
return annotations;
}
private void rotatePath(Path path, float degree) {
Matrix mMatrix = new Matrix();
RectF bounds = new RectF();
path.computeBounds(bounds, true);
mMatrix.postRotate(degree, (bounds.right + bounds.left) / 2, (bounds.bottom + bounds.top) / 2);
path.transform(mMatrix);
}
}
2. In your activity, create the AnnotationView and assign your image to it, then append this view to your root view.
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AnnotationView mPreview = (FrameLayout) findViewById(R.id.camera_preview);
AnnotationView mAnnotationView = new AnnotationView(this);
Bitmap bitmap;
try {
bitmap = CBitmapUtil.decode(mPictureFile); // Get your image as a bitmap
mAnnotationView.setImageBitmap(bitmap);
mPreview.addView(mAnnotationView, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
} catch (FileNotFoundException e) {
e.printStackTrace();
Toast.makeText(this, "Photo cannot be saved, please try again later.", Toast.LENGTH_SHORT).show();
}
}

How to Zoom in/out imageView on Click using java in Android?

i have followed this tutorial to zoom in imageview on touch but i have an activity that have 15 images and when i click on any one image it will open new Activity and will zoom in that clicked image on new Activity so my question is
How can i pass clicked image src to nextActivity so that my single method will be applicable to zoom in for all images.
On new Activity (Zoom in) when i clicked on it how can i zoom out that image again.
I have followed this:Zoom in
Its successfully zoom in an imageview but i have no idea how to write code for zoom out.Can someone please help me on this task.
Any Tutorials will be appreciated but link must contain same code as it is in this url with some few changes for zoom out
public class TouchImageView extends ImageView {
Matrix matrix;
static final int NONE = 0;
static final int DRAG = 1;
static int ZOOM = 2;
static int mode = NONE;
public int isundo = 0;
PointF last = new PointF();
PointF start = new PointF();
float minScale = 0f;
float maxScale = 1f;
float[] m;
int viewWidth, viewHeight;
static final int CLICK = 3;
float saveScale = 1f;
protected float origWidth, origHeight;
int oldMeasuredWidth, oldMeasuredHeight;
float bmWidth, bmHeight;
ScaleGestureDetector mScaleDetector;
Context context;
public TouchImageView(Context context) {
super(context);
if (isundo == 0) {
sharedConstructing(context);
}
}
public TouchImageView(Context context, AttributeSet attrs) {
super(context, attrs);
if (isundo == 0) {
sharedConstructing(context);
}
}
private void sharedConstructing(Context context) {
super.setClickable(true);
this.context = context;
mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
matrix = new Matrix();
m = new float[9];
setImageMatrix(matrix);
setScaleType(ScaleType.MATRIX);
setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
mScaleDetector.onTouchEvent(event);
PointF curr = new PointF(event.getX(), event.getY());
if (isundo == 0) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
last.set(curr);
start.set(last);
mode = DRAG;
break;
case MotionEvent.ACTION_MOVE:
if (mode == DRAG) {
float deltaX = curr.x - last.x;
float deltaY = curr.y - last.y;
matrix.postTranslate(deltaX, deltaY);
fixTrans();
last.set(curr.x, curr.y);
}
break;
case MotionEvent.ACTION_UP:
mode = NONE;
int xDiff = (int) Math.abs(curr.x - start.x);
int yDiff = (int) Math.abs(curr.y - start.y);
if (xDiff < CLICK && yDiff < CLICK)
performClick();
break;
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
break;
}
}
setImageMatrix(matrix);
invalidate();
return true; // indicate event was handled
}
});
}
public void stopInterceptEvent() {
getParent().requestDisallowInterceptTouchEvent(true);
}
public void startInterceptEvent() {
getParent().requestDisallowInterceptTouchEvent(false);
}
#Override
public void setImageBitmap(Bitmap bm) {
super.setImageBitmap(bm);
if (bm != null) {
origWidth = bm.getWidth();
origHeight = bm.getHeight();
}
}
public void setMaxZoom(float x) {
maxScale = x;
}
private class ScaleListener extends
ScaleGestureDetector.SimpleOnScaleGestureListener {
#Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
mode = ZOOM;
return true;
}
#Override
public boolean onScale(ScaleGestureDetector detector) {
float mScaleFactor = detector.getScaleFactor();
float origScale = saveScale;
saveScale *= mScaleFactor;
if (saveScale > maxScale) {
saveScale = maxScale;
mScaleFactor = maxScale / origScale;
} else if (saveScale < minScale) {
saveScale = minScale;
mScaleFactor = minScale / origScale;
}
if (origWidth * saveScale <= viewWidth
|| origHeight * saveScale <= viewHeight)
matrix.postScale(mScaleFactor, mScaleFactor, viewWidth / 2,
viewHeight / 2);
else
matrix.postScale(mScaleFactor, mScaleFactor,
detector.getFocusX(), detector.getFocusY());
fixTrans();
return true;
}
}
void fixTrans() {
matrix.getValues(m);
float transX = m[Matrix.MTRANS_X];
float transY = m[Matrix.MTRANS_Y];
float fixTransX = getFixTrans(transX, viewWidth, origWidth * saveScale);
float fixTransY = getFixTrans(transY, viewHeight, origHeight
* saveScale);
if (fixTransX != 0 || fixTransY != 0)
matrix.postTranslate(fixTransX, fixTransY);
}
float getFixTrans(float trans, float viewSize, float contentSize) {
float minTrans, maxTrans;
if (contentSize <= viewSize) {
minTrans = 0;
maxTrans = viewSize - contentSize;
} else {
minTrans = viewSize - contentSize;
maxTrans = 0;
}
if (trans < minTrans)
return -trans + minTrans;
if (trans > maxTrans)
return -trans + maxTrans;
return 0;
}
float getFixDragTrans(float delta, float viewSize, float contentSize) {
if (contentSize <= viewSize) {
return 0;
}
return delta;
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
viewWidth = MeasureSpec.getSize(widthMeasureSpec);
viewHeight = MeasureSpec.getSize(heightMeasureSpec);
//
// Rescales image on rotation
//
if (oldMeasuredHeight == viewWidth && oldMeasuredHeight == viewHeight
|| viewWidth == 0 || viewHeight == 0)
return;
oldMeasuredHeight = viewHeight;
oldMeasuredWidth = viewWidth;
if (saveScale == 1) {
// Fit to screen.
float scale;
Drawable drawable = getDrawable();
if (drawable == null || drawable.getIntrinsicWidth() == 0
|| drawable.getIntrinsicHeight() == 0)
return;
int bmWidth = drawable.getIntrinsicWidth();
int bmHeight = drawable.getIntrinsicHeight();
float scaleX = (float) viewWidth / (float) bmWidth;
float scaleY = (float) viewHeight / (float) bmHeight;
scale = Math.min(scaleX, scaleY);
matrix.setScale(scale, scale);
// Center the image
float redundantYSpace = (float) viewHeight
- (scale * (float) bmHeight);
float redundantXSpace = (float) viewWidth
- (scale * (float) bmWidth);
redundantYSpace /= (float) 2;
redundantXSpace /= (float) 2;
matrix.postTranslate(redundantXSpace, redundantYSpace);
origWidth = viewWidth - 2 * redundantXSpace;
origHeight = viewHeight - 2 * redundantYSpace;
setImageMatrix(matrix);
}
fixTrans();
}
}
use this way like ::---->>>
TouchImageView iv = new TouchImageView(getApplicationContext());
iv.setImageBitmap(editedImage);
layout.addView(iv);

How do I Implement Pinch Zoom in following code in android [duplicate]

I have a ListView with set of images. On clicking any of them, the clicked image will appear on a new activity and at the center of the activity in ImageView, also it is Zoomable. The Problem is when i zoom the image it gains Zoom but also moves like drag and drop. I should eliminate that movement of the image and should only be zoomable from the center of the activity.
ZoomInZoomOutActivity.java
public class ZoomInZoomOutActivity extends Activity implements OnTouchListener
{
private static final String TAG = "Touch";
#SuppressWarnings("unused")
private static final float MIN_ZOOM = 1f,MAX_ZOOM = 1f;
Matrix matrix = new Matrix();
Matrix savedMatrix = new Matrix();
static final int NONE = 0;
static final int DRAG = 1;
static final int ZOOM = 2;
int mode = NONE;
PointF start = new PointF();
PointF mid = new PointF();
float oldDist = 1f;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.imagedisp);
Bundle extras = getIntent().getExtras();
long id =extras.getLong("ID");
String s=String.valueOf(id);
ImageView view;
view = (ImageView) findViewById(R.id.imageView1);
view.setOnTouchListener(this);
if (s.equals("0"))
{
view.setImageResource(R.drawable.img1);
}
else if (s.equals("1"))
{
view.setImageResource(R.drawable.img2);
}
else if (s.equals("2"))
{
view.setImageResource(R.drawable.img3);
}
else
{
view.setImageResource(R.drawable.img4);
}
}
public boolean onTouch(View v, MotionEvent event)
{
ImageView view = (ImageView) v;
view.setScaleType(ImageView.ScaleType.MATRIX);
float scale;
switch (event.getAction() & MotionEvent.ACTION_MASK)
{
/*case MotionEvent.ACTION_DOWN:
savedMatrix.set(matrix);
start.set(event.getX(), event.getY());
Log.d(TAG, "mode=DRAG");
mode = DRAG;
break; */
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
Log.d(TAG, "mode=NONE");
break;
case MotionEvent.ACTION_POINTER_DOWN:
oldDist = spacing(event);
Log.d(TAG, "oldDist=" + oldDist);
if (oldDist > 5f) {
savedMatrix.set(matrix);
midPoint(mid, event);
mode = ZOOM;
Log.d(TAG, "mode=ZOOM");
}
break;
case MotionEvent.ACTION_MOVE:
if (mode == DRAG)
{
matrix.set(savedMatrix);
matrix.postTranslate(event.getX() - start.x, event.getY() - start.y);
}
else if (mode == ZOOM)
{
float newDist = spacing(event);
Log.d(TAG, "newDist=" + newDist);
if (newDist > 5f)
{
matrix.set(savedMatrix);
scale = newDist / oldDist;
matrix.postScale(scale, scale, mid.x, mid.y);
}
}
break;
}
view.setImageMatrix(matrix);
return true;
}
private float spacing(MotionEvent event)
{
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return FloatMath.sqrt(x * x + y * y);
}
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);
}
}
imagedisp.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center">
<ImageView android:layout_width="fill_parent"
android:id="#+id/imageView1"
android:src="#drawable/img1"
android:layout_height="fill_parent"
android:scaleType="centerInside">
</ImageView>
</LinearLayout>
Try this code:
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.widget.ImageView;
/**
* Extends Android ImageView to include pinch zooming and panning.
*/
public class TouchImageView extends ImageView
{
Matrix matrix = new Matrix();
// We can be in one of these 3 states
static final int NONE = 0;
static final int DRAG = 1;
static final int ZOOM = 2;
int mode = NONE;
// Remember some things for zooming
PointF last = new PointF();
PointF start = new PointF();
float minScale = 1f;
float maxScale = 3f;
float[] m;
float redundantXSpace, redundantYSpace;
float width, height;
static final int CLICK = 3;
float saveScale = 1f;
float right, bottom, origWidth, origHeight, bmWidth, bmHeight;
ScaleGestureDetector mScaleDetector;
Context context;
public TouchImageView(Context context)
{
super(context);
sharedConstructing(context);
}
public TouchImageView(Context context, AttributeSet attrs)
{
super(context, attrs);
sharedConstructing(context);
}
private void sharedConstructing(Context context)
{
super.setClickable(true);
this.context = context;
mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
matrix.setTranslate(1f, 1f);
m = new float[9];
setImageMatrix(matrix);
setScaleType(ScaleType.MATRIX);
setOnTouchListener(new OnTouchListener()
{
#Override
public boolean onTouch(View v, MotionEvent event)
{
mScaleDetector.onTouchEvent(event);
matrix.getValues(m);
float x = m[Matrix.MTRANS_X];
float y = m[Matrix.MTRANS_Y];
PointF curr = new PointF(event.getX(), event.getY());
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
last.set(event.getX(), event.getY());
start.set(last);
mode = DRAG;
break;
case MotionEvent.ACTION_MOVE:
if (mode == DRAG)
{
float deltaX = curr.x - last.x;
float deltaY = curr.y - last.y;
float scaleWidth = Math.round(origWidth * saveScale);
float scaleHeight = Math.round(origHeight * saveScale);
if (scaleWidth < width)
{
deltaX = 0;
if (y + deltaY > 0)
deltaY = -y;
else if (y + deltaY < -bottom)
deltaY = -(y + bottom);
}
else if (scaleHeight < height)
{
deltaY = 0;
if (x + deltaX > 0)
deltaX = -x;
else if (x + deltaX < -right)
deltaX = -(x + right);
}
else
{
if (x + deltaX > 0)
deltaX = -x;
else if (x + deltaX < -right)
deltaX = -(x + right);
if (y + deltaY > 0)
deltaY = -y;
else if (y + deltaY < -bottom)
deltaY = -(y + bottom);
}
matrix.postTranslate(deltaX, deltaY);
last.set(curr.x, curr.y);
}
break;
case MotionEvent.ACTION_UP:
mode = NONE;
int xDiff = (int) Math.abs(curr.x - start.x);
int yDiff = (int) Math.abs(curr.y - start.y);
if (xDiff < CLICK && yDiff < CLICK)
performClick();
break;
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
break;
}
setImageMatrix(matrix);
invalidate();
return true; // indicate event was handled
}
});
}
#Override
public void setImageBitmap(Bitmap bm)
{
super.setImageBitmap(bm);
if (bm != null)
{
bmWidth = bm.getWidth();
bmHeight = bm.getHeight();
}
}
public void setMaxZoom(float x)
{
maxScale = x;
}
private class ScaleListener extends
ScaleGestureDetector.SimpleOnScaleGestureListener
{
#Override
public boolean onScaleBegin(ScaleGestureDetector detector)
{
mode = ZOOM;
return true;
}
#Override
public boolean onScale(ScaleGestureDetector detector)
{
float mScaleFactor = (float) Math.min(
Math.max(.95f, detector.getScaleFactor()), 1.05);
float origScale = saveScale;
saveScale *= mScaleFactor;
if (saveScale > maxScale)
{
saveScale = maxScale;
mScaleFactor = maxScale / origScale;
}
else if (saveScale < minScale)
{
saveScale = minScale;
mScaleFactor = minScale / origScale;
}
right = width * saveScale - width - (2 * redundantXSpace * saveScale);
bottom = height * saveScale - height
- (2 * redundantYSpace * saveScale);
if (origWidth * saveScale <= width || origHeight * saveScale <= height)
{
matrix.postScale(mScaleFactor, mScaleFactor, width / 2, height / 2);
if (mScaleFactor < 1)
{
matrix.getValues(m);
float x = m[Matrix.MTRANS_X];
float y = m[Matrix.MTRANS_Y];
if (mScaleFactor < 1)
{
if (Math.round(origWidth * saveScale) < width)
{
if (y < -bottom)
matrix.postTranslate(0, -(y + bottom));
else if (y > 0)
matrix.postTranslate(0, -y);
}
else
{
if (x < -right)
matrix.postTranslate(-(x + right), 0);
else if (x > 0)
matrix.postTranslate(-x, 0);
}
}
}
}
else
{
matrix.postScale(mScaleFactor, mScaleFactor, detector.getFocusX(),
detector.getFocusY());
matrix.getValues(m);
float x = m[Matrix.MTRANS_X];
float y = m[Matrix.MTRANS_Y];
if (mScaleFactor < 1)
{
if (x < -right)
matrix.postTranslate(-(x + right), 0);
else if (x > 0)
matrix.postTranslate(-x, 0);
if (y < -bottom)
matrix.postTranslate(0, -(y + bottom));
else if (y > 0)
matrix.postTranslate(0, -y);
}
}
return true;
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
width = MeasureSpec.getSize(widthMeasureSpec);
height = MeasureSpec.getSize(heightMeasureSpec);
// Fit to screen.
float scale;
float scaleX = (float) width / (float) bmWidth;
float scaleY = (float) height / (float) bmHeight;
scale = Math.min(scaleX, scaleY);
matrix.setScale(scale, scale);
setImageMatrix(matrix);
saveScale = 1f;
// Center the image
redundantYSpace = (float) height - (scale * (float) bmHeight);
redundantXSpace = (float) width - (scale * (float) bmWidth);
redundantYSpace /= (float) 2;
redundantXSpace /= (float) 2;
matrix.postTranslate(redundantXSpace, redundantYSpace);
origWidth = width - 2 * redundantXSpace;
origHeight = height - 2 * redundantYSpace;
right = width * saveScale - width - (2 * redundantXSpace * saveScale);
bottom = height * saveScale - height - (2 * redundantYSpace * saveScale);
setImageMatrix(matrix);
}
}

How does TouchImageView works?

I have good working TouchImageView and i want to know how does it work in a code :
What i just want to do is be able to pinch to zoom, or use double tap to zoom on any imageview i choose, and when i zoom back i return to the original size of the image.
TouchImageView.java :
public class TouchImageView extends ImageView {
Matrix matrix = new Matrix();
static final int NONE = 0;
static final int DRAG = 1;
static final int ZOOM = 2;
int mode = NONE;
PointF last = new PointF();
PointF start = new PointF();
float minScale = 1f;
float maxScale = 3f;
float[] m;
float redundantXSpace, redundantYSpace;
float width, height;
static final int CLICK = 3;
float saveScale = 1f;
float right, bottom, origWidth, origHeight, bmWidth, bmHeight;
ScaleGestureDetector mScaleDetector;
Context context;
public TouchImageView(Context context) {
super(context);
super.setClickable(true);
this.context = context;
mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
matrix.setTranslate(1f, 1f);
m = new float[9];
setImageMatrix(matrix);
setScaleType(ScaleType.MATRIX);
setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
mScaleDetector.onTouchEvent(event);
matrix.getValues(m);
float x = m[Matrix.MTRANS_X];
float y = m[Matrix.MTRANS_Y];
PointF curr = new PointF(event.getX(), event.getY());
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
last.set(event.getX(), event.getY());
start.set(last);
mode = DRAG;
break;
case MotionEvent.ACTION_MOVE:
if (mode == DRAG) {
float deltaX = curr.x - last.x;
float deltaY = curr.y - last.y;
float scaleWidth = Math.round(origWidth * saveScale);
float scaleHeight = Math.round(origHeight * saveScale);
if (scaleWidth < width) {
deltaX = 0;
if (y + deltaY > 0)
deltaY = -y;
else if (y + deltaY < -bottom)
deltaY = -(y + bottom);
} else if (scaleHeight < height) {
deltaY = 0;
if (x + deltaX > 0)
deltaX = -x;
else if (x + deltaX < -right)
deltaX = -(x + right);
} else {
if (x + deltaX > 0)
deltaX = -x;
else if (x + deltaX < -right)
deltaX = -(x + right);
if (y + deltaY > 0)
deltaY = -y;
else if (y + deltaY < -bottom)
deltaY = -(y + bottom);
}
matrix.postTranslate(deltaX, deltaY);
last.set(curr.x, curr.y);
}
break;
case MotionEvent.ACTION_UP:
mode = NONE;
int xDiff = (int) Math.abs(curr.x - start.x);
int yDiff = (int) Math.abs(curr.y - start.y);
if (xDiff < CLICK && yDiff < CLICK)
performClick();
break;
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
break;
}
setImageMatrix(matrix);
invalidate();
return true; // indicate event was handled
}
});
}
#Override
public void setImageBitmap(Bitmap bm) {
super.setImageBitmap(bm);
bmWidth = bm.getWidth();
bmHeight = bm.getHeight();
}
public void setMaxZoom(float x)
{
maxScale = x;
}
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
#Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
mode = ZOOM;
return true;
}
#Override
public boolean onScale(ScaleGestureDetector detector) {
float mScaleFactor = (float)Math.min(Math.max(.95f, detector.getScaleFactor()), 1.05);
float origScale = saveScale;
saveScale *= mScaleFactor;
if (saveScale > maxScale) {
saveScale = maxScale;
mScaleFactor = maxScale / origScale;
} else if (saveScale < minScale) {
saveScale = minScale;
mScaleFactor = minScale / origScale;
}
right = width * saveScale - width - (2 * redundantXSpace * saveScale);
bottom = height * saveScale - height - (2 * redundantYSpace * saveScale);
if (origWidth * saveScale <= width || origHeight * saveScale <= height) {
matrix.postScale(mScaleFactor, mScaleFactor, width / 2, height / 2);
if (mScaleFactor < 1) {
matrix.getValues(m);
float x = m[Matrix.MTRANS_X];
float y = m[Matrix.MTRANS_Y];
if (mScaleFactor < 1) {
if (Math.round(origWidth * saveScale) < width) {
if (y < -bottom)
matrix.postTranslate(0, -(y + bottom));
else if (y > 0)
matrix.postTranslate(0, -y);
} else {
if (x < -right)
matrix.postTranslate(-(x + right), 0);
else if (x > 0)
matrix.postTranslate(-x, 0);
}
}
}
} else {
matrix.postScale(mScaleFactor, mScaleFactor, detector.getFocusX(), detector.getFocusY());
matrix.getValues(m);
float x = m[Matrix.MTRANS_X];
float y = m[Matrix.MTRANS_Y];
if (mScaleFactor < 1) {
if (x < -right)
matrix.postTranslate(-(x + right), 0);
else if (x > 0)
matrix.postTranslate(-x, 0);
if (y < -bottom)
matrix.postTranslate(0, -(y + bottom));
else if (y > 0)
matrix.postTranslate(0, -y);
}
}
return true;
}
}
#Override
protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec)
{
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
width = MeasureSpec.getSize(widthMeasureSpec);
height = MeasureSpec.getSize(heightMeasureSpec);
//Fit to screen.
float scale;
float scaleX = (float)width / (float)bmWidth;
float scaleY = (float)height / (float)bmHeight;
scale = Math.min(scaleX, scaleY);
matrix.setScale(scale, scale);
setImageMatrix(matrix);
saveScale = 1f;
// Center the image
redundantYSpace = (float)height - (scale * (float)bmHeight) ;
redundantXSpace = (float)width - (scale * (float)bmWidth);
redundantYSpace /= (float)2;
redundantXSpace /= (float)2;
matrix.postTranslate(redundantXSpace, redundantYSpace);
origWidth = width - 2 * redundantXSpace;
origHeight = height - 2 * redundantYSpace;
right = width * saveScale - width - (2 * redundantXSpace * saveScale);
bottom = height * saveScale - height - (2 * redundantYSpace * saveScale);
setImageMatrix(matrix);
}
}
To use is i created a private class :
private class CreateImage extends AsyncTask<String, Void, Drawable> {
protected void onPreExecute() {
}
protected Drawable doInBackground(String... urls) {
InputStream is;
Drawable d = null ;
try {
is = (InputStream)new URL(urls[0]).getContent();
d = Drawable.createFromStream(is, "Image");
return d;
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return d;
}
protected void onPostExecute(Drawable d) {
touch.setMaxZoom(4f);
touch.setImageDrawable(d);
setContentView(touch);
}
}
public void createUrlImage(String url){
new CreateImage().execute(url);
}
and in the onCreate() i put createUrlImage(url).
I modified TouchImageView by adding :
public void setImageDrawable(Drawable dr) {
super.setImageDrawable(dr);
bmWidth = dr.getIntrinsicWidth();
bmHeight = dr.getIntrinsicHeight();
}
EDIT: Double Tap Zoom, Fling and other features have been added to TouchImageView since I originally answered this question. You can check it out on github here.
I added some usage details to the original post here. The code already has pinch zoom and panning, along with boundaries. Also, zooming out will return you to the original sized image.
Adding double tap zoom will take more work. You'll have to use a GestureDetector and override onDoubleTap and onSingleTapConfirmed. You'll then want to make sure you pass your touch events to gestureDetector, without interfering with the rest of the code (see how events are passed to mScaleDetector at the beginning of onTouch). You'll want to get rid of the call to performClick() in ACTION_UP and instead place it in onSingleTapConfirmed. You can check this answer for some skeletal code to get you started in implementing GestureDetector.
Let me know if you manage to get double tap zoom solid and I'll add your changes to the original post and the Github repo.

Categories