using nine patch images to draw to a canvas in android studio - java

I am currently using canvas.drawCircle() method to draw dots that represent objects on my screen. I am having trouble using nine patch images instead of circles. Could someone provide an example on how I can implement this?
public class SnakeView extends View {
private Paint mPaint = new Paint();
private TileType snakeViewMap[][];
public SnakeView(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
}
public void setSnakeViewMap(TileType[][] map) { this.snakeViewMap = map; }
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if(snakeViewMap != null) {
float tileSizeX = canvas.getWidth() / snakeViewMap.length;
float tileSizeY = canvas.getHeight() / snakeViewMap[0].length;
float circleSize = Math.min(tileSizeX, tileSizeY) / 2;
for (int x = 0; x < snakeViewMap.length; x++) {
for (int y = 0; y <snakeViewMap[x].length; y++) {
switch (snakeViewMap[x][y]) {
case Nothing:
mPaint.setColor(Color.WHITE);
break;
case Wall:
mPaint.setColor(Color.RED);
break;
case SnakeHead:
mPaint.setColor(Color.BLACK);
break;
case SnakeTail:
mPaint.setColor(Color.GREEN);
break;
case Apple:
mPaint.setColor(Color.RED);
break;
}
canvas.drawCircle(x * tileSizeX + tileSizeX / 2f + circleSize / 2, y * tileSizeY + tileSizeY /2f + circleSize / 2, circleSize, mPaint);
}
}
}
}
}

Related

Drag a rectangle on Canvas Android

I'm drawing a rectangle on a Canvas in Android. How do I drag it around on the screen? I have an onTouchEvent() method in my class that listens to MotionEvent(s). How do I use this to drag my rectangle around while preserving it's size.
My code is as follows:
public class CustomSquareView3 extends View {
private Rect rect;
private Paint paint;
public static int rotation = 45;
Canvas canvas;
int x1 = 200;
int x2 = 400;
int y1 = 200;
int y2 = 400;
public CustomSquareView3(Context context){
super(context);
int x = 50;
int y = 50;
int sideLength = 200;
rect = new Rect(x1,y1, x2, y2);
paint = new Paint();
paint.setColor(Color.GRAY);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.WHITE);
canvas.save();
canvas.rotate(rotation, (x1+x2)/2, (y1+y2)/2);
canvas.drawRect(rect, paint);
Paint paint2 = new Paint();
paint2.setColor(Color.WHITE);
paint2.setTextSize(50);
canvas.drawText("Hi", (x1+x2)/2, (y1+y2)/2, paint2);
canvas.restore();
}
#Override
public boolean onTouchEvent(MotionEvent event) {
int motionEvent = event.getAction();
float xMove = event.getX();
float yMove = event.getY();
switch (motionEvent){
case MotionEvent.ACTION_DOWN : {
x1 = (int) event.getX();
y1 = (int) event.getY();
rect = new Rect(x1, y1, x2, y2);
break;
}
case MotionEvent.ACTION_MOVE : {
x1 = (int) event.getX();
y1 = (int) event.getY();
rect = new Rect(x1, y1, x2, y2);
break;
}
case MotionEvent.ACTION_UP : {
x1 = (int) event.getX();
y1 = (int) event.getY();
rect = new Rect(x1, y1, x2, y2);
break;
}
default:
return false;
}
invalidate();
return true;
}
}
The above code resizes the rectangle every time I touch the screen. How do I get a smooth drag gesture in the code such that the size of the rectangle is maintained when it is dragged around the screen?
See this example:
class ViewPort extends View {
List<Layer> layers = new LinkedList<Layer>();
int[] ids = {R.drawable.layer0, R.drawable.layer1, R.drawable.layer2};
public ViewPort(Context context) {
super(context);
Resources res = getResources();
for (int i = 0; i < ids.length; i++) {
Layer l = new Layer(context, this, BitmapFactory.decodeResource(res, ids[i]));
layers.add(l);
}
}
#Override
protected void onDraw(Canvas canvas) {
for (Layer l : layers) {
l.draw(canvas);
}
}
private Layer target;
#Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
target = null;
for (int i = layers.size() - 1; i >= 0; i--) {
Layer l = layers.get(i);
if (l.contains(event)) {
target = l;
layers.remove(l);
layers.add(l);
invalidate();
break;
}
}
}
if (target == null) {
return false;
}
return target.onTouchEvent(event);
}
}
class Layer implements MatrixGestureDetector.OnMatrixChangeListener {
Matrix matrix = new Matrix();
Matrix inverse = new Matrix();
RectF bounds;
View parent;
Bitmap bitmap;
MatrixGestureDetector mgd = new MatrixGestureDetector(matrix, this);
public Layer(Context ctx, View p, Bitmap b) {
parent = p;
bitmap = b;
bounds = new RectF(0, 0, b.getWidth(), b.getHeight());
matrix.postTranslate(50 + (float) Math.random() * 50, 50 + (float) Math.random() * 50);
}
public boolean contains(MotionEvent event) {
matrix.invert(inverse);
float[] pts = {event.getX(), event.getY()};
inverse.mapPoints(pts);
if (!bounds.contains(pts[0], pts[1])) {
return false;
}
return Color.alpha(bitmap.getPixel((int) pts[0], (int) pts[1])) != 0;
}
public boolean onTouchEvent(MotionEvent event) {
mgd.onTouchEvent(event);
return true;
}
#Override
public void onChange(Matrix matrix) {
parent.invalidate();
}
public void draw(Canvas canvas) {
canvas.drawBitmap(bitmap, matrix, null);
}
}
class MatrixGestureDetector {
private static final String TAG = "MatrixGestureDetector";
private int ptpIdx = 0;
private Matrix mTempMatrix = new Matrix();
private Matrix mMatrix;
private OnMatrixChangeListener mListener;
private float[] mSrc = new float[4];
private float[] mDst = new float[4];
private int mCount;
interface OnMatrixChangeListener {
void onChange(Matrix matrix);
}
public MatrixGestureDetector(Matrix matrix, MatrixGestureDetector.OnMatrixChangeListener listener) {
this.mMatrix = matrix;
this.mListener = listener;
}
public void onTouchEvent(MotionEvent event) {
if (event.getPointerCount() > 2) {
return;
}
int action = event.getActionMasked();
int index = event.getActionIndex();
switch (action) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN:
int idx = index * 2;
mSrc[idx] = event.getX(index);
mSrc[idx + 1] = event.getY(index);
mCount++;
ptpIdx = 0;
break;
case MotionEvent.ACTION_MOVE:
for (int i = 0; i < mCount; i++) {
idx = ptpIdx + i * 2;
mDst[idx] = event.getX(i);
mDst[idx + 1] = event.getY(i);
}
mTempMatrix.setPolyToPoly(mSrc, ptpIdx, mDst, ptpIdx, mCount);
mMatrix.postConcat(mTempMatrix);
if(mListener != null) {
mListener.onChange(mMatrix);
}
System.arraycopy(mDst, 0, mSrc, 0, mDst.length);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
if (event.getPointerId(index) == 0) ptpIdx = 2;
mCount--;
break;
}
}
}
You have to redo it a little. Use your rectangle instead of bitmaps.

first path isn't painted

I have made a custom view to paint over a bitmap. The problem is when try to paint the first touch don't show any thing and the color also changed in the next time , the second problem is that the when i save the image no thing is showed from the painted colores
Here is my code:
public class DrawView extends android.support.v7.widget.AppCompatImageView {
private ArrayList<ColouredPoint> paths ;
private ColouredPoint mPath;
private Paint mPaint;
private static final float TOUCH_TOLERANCE = 4;
boolean erase;
// Current used colour
private int mCurrColour;
public void setErase(boolean era){
erase=era;
}
public void setColor(int colour) {
mCurrColour = colour;
}
public DrawView(Context context) {
super(context);
init();
}
// XML constructor
public DrawView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
paths = new ArrayList<>();
mPaint = new Paint();
mPath = new ColouredPoint(mCurrColour);
mPaint.setColor(mCurrColour);
mPaint.setDither(true);
mPaint.setAntiAlias(true);
mPaint.setStrokeWidth(15);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
}
private float mX, mY;
#Override
public boolean onTouchEvent(MotionEvent event) {
// Capture a reference to each touch for drawing
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mPath.reset();
mPath.moveTo(x, y);
mX = x;
mY = y;
break;
case MotionEvent.ACTION_MOVE:
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
mX = x;
mY = y;}
break;
case MotionEvent.ACTION_UP:
mPath.lineTo(mX, mY);
mPath = new ColouredPoint(mCurrColour);
paths.add(mPath);
break;
}
return super.onTouchEvent(event);
}
#Override
protected void onDraw(Canvas c) {
// Let the image be drawn first
super.onDraw(c);
// Draw your custom points here
if(!erase){
for (ColouredPoint i:paths) {
mPaint.setColor(i.colour);
c.drawPath(i, mPaint);}}
else if (paths.size()>0){
paths.remove(paths.size()-1);
} else {
Toast.makeText(getContext(), "Undo unknown", Toast.LENGTH_SHORT)
.show();}}
/**
* Class to store the coordinate and the colour of the point.
*/
private class ColouredPoint extends Path{
int colour;
public ColouredPoint(int colour) {
this.colour = colour;
}
}
}
how to fix this ?

How to make usable padding space around circle in canvas (Android)

I am having problems displaying dots on the outer ring of a circle. When a dot is placed at one of the edges of the circle, the dot is half cut off . Screenshot: https://drive.google.com/file/d/0B9BaYaKRY3v3Y2hXYkpSOE1nY28/edit?usp=sharing
I simply want to make the circles radius a litte smaller so there is some space around it where the outer dots have got some space. Of course the circle must still stay in the middle of the view. Tipps on how to do this are very appreciated.
The working code blow is fully working accept for the fact that the dots are being cut off. (Thanks to #Sherif elKhatib for the help on creating a 2 color circle)
public class PercentView extends View {
public PercentView(Context context) {
super(context);
init();
}
public PercentView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public PercentView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
paint = new Paint();
paint.setColor(Color.parseColor("#3498db"));
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.FILL);
bgpaint = new Paint();
bgpaint.setColor(Color.parseColor("#2980b9"));
bgpaint.setAntiAlias(true);
bgpaint.setStyle(Paint.Style.FILL);
rect = new RectF();
circlePaint = new Paint();
}
Paint paint;
Paint bgpaint;
RectF rect;
float percentage = 5;
Paint circlePaint;
float[] dots = new float[1000];
int dotsNum = -1;
String[] colorCode = new String[1000];
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// draw background circle anyway
canvas.drawArc(rect, -90, 360, true, bgpaint);
if (percentage != 0) {
int left = 0;
int width = getWidth();
int top = 0;
rect.set(left, top, left + width, top + width);
canvas.drawArc(rect, -90, (float) (3.6 * percentage), true, paint);
for (int i = 0; i <= dotsNum; i++) {
circlePaint.setAntiAlias(true);
circlePaint.setColor(Color.parseColor(colorCode[i]));
circlePaint.setStyle(Paint.Style.FILL);
float dotX = (float) (this.getWidth() / 2 + this.getWidth() / 2
* Math.cos((dots[i] * 3.6 - 90) * Math.PI / 180));
float dotY = (float) (this.getHeight() / 2 + this.getWidth()
/ 2 * Math.sin((dots[i] * 3.6 - 90) * Math.PI / 180));
canvas.drawCircle(dotX, dotY, 30, circlePaint);
}
}
}
public void setPercentage(float inpercentage) {
this.percentage = inpercentage;
invalidate();
}
public void setDot(int type) {
dotsNum++;
switch (type) {
case 0:
colorCode[dotsNum] = "#27ae60";
break;
case 1:
colorCode[dotsNum] = "#f1c40f";
break;
case 2:
colorCode[dotsNum] = "#e74c3c";
break;
case 3:
colorCode[dotsNum] = "#34495e";
break;
}
dots[dotsNum] = percentage;
invalidate();
}
}
The only one working approach for me was that piece of code "width = getWidth() - padding". Kudos #Catherine.

Signatures in Android

I want to make a class which captures a human signature for my Android app. I have this code so far:
public class DrawView extends View implements OnTouchListener {
private static final String TAG = "DrawView";
List<Point> points = new ArrayList<Point>();
Paint paint = new Paint();
long oldTime = 0;
public DrawView(Context context) {
super(context);
setFocusable(true);
setFocusableInTouchMode(true);
this.setOnTouchListener(this);
// paint.setColor(Color.BLACK);
// paint.setAntiAlias(true);
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(2);
paint.setColor(Color.BLACK);
}
#Override
public void onDraw(Canvas canvas) {
Path path = new Path();
if (points.size() > 1) {
for (int i = points.size() - 2; i < points.size(); i++) {
if (i >= 0) {
Point point = points.get(i);
if (i == 0) {
Point next = points.get(i + 1);
point.dx = ((next.x - point.x) / 3);
point.dy = ((next.y - point.y) / 3);
} else if (i == points.size() - 1) {
Point prev = points.get(i - 1);
point.dx = ((point.x - prev.x) / 3);
point.dy = ((point.y - prev.y) / 3);
} else {
Point next = points.get(i + 1);
Point prev = points.get(i - 1);
point.dx = ((next.x - prev.x) / 3);
point.dy = ((next.y - prev.y) / 3);
}
}
}
}
boolean first = true;
for (int i = 0; i < points.size(); i++) {
Point point = points.get(i);
if (first) {
first = false;
path.moveTo(point.x, point.y);
} else {
Point prev = points.get(i - 1);
path.cubicTo(prev.x + prev.dx, prev.y + prev.dy, point.x
- point.dx, point.y - point.dy, point.x, point.y);
}
}
canvas.drawPath(path, paint);
}
public boolean onTouch(View view, MotionEvent event) {
if (event.getAction() != MotionEvent.ACTION_UP) {
Point point = new Point();
point.x = event.getX();
point.y = event.getY();
points.add(point);
invalidate();
return true;
}
return super.onTouchEvent(event);
}
public boolean checkTime() {
//Check if there was an input 400 ms ago
long newTime = System.currentTimeMillis();
long diffirence = newTime - oldTime;
if (oldTime == 0) {
oldTime = System.currentTimeMillis();
return true;
} else if (diffirence <= 400) {
oldTime = System.currentTimeMillis();
return true;
}
return false;
}
}
class Point {
float x, y;
float dx, dy;
#Override
public String toString() {
return x + ", " + y;
}
}
The problem is that the line will connect to the latest point when I start drawing again, even when I stop drawing for a while. This is of course not very useful for capturing human signatures, that's why I created the checkTime method. If you stop drawing for 400ms it returns false, when you start drawing again it will start a new line which is not connected to the old line. I only just don't know how I can implement my method, I tried a lot but the line keeps connecting to the latest point, maybe someone can help me.
It's probably faster to create the path in onTouch and only draw it in onDraw.
Replace onTouch with
Path path = new Path();
int prevx=0;
int prevy=0;
int prevdx=0;
int prevdy=0;
public boolean onTouch(View view, MotionEvent event)
{
int x = event.getX();
int y = event.getY();
int dx = (x-prevx)/3;
int dy = (y-prevy)/3;
if(event.getAction() == MotionEvent.ACTION_DOWN)
{
path.moveTo(x, y);
}
if(event.getAction() == MotionEvent.ACTION_MOVE)
{
path.cubicTo(prevx + prevdx, prevy + prevdy, x - dx, y - dy, x, y);
}
prevx=x;
prevy=y;
prevdx=dx;
prevdy=dy;
invalidate();
return true;
}
onDraw will be just
public void onDraw(Canvas canvas)
{
canvas.drawPath(path, paint);
}
I used this post from Lars Vogel, but many thanks to Marc Van Daele!
This is code wich paints the View:
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
public class SingleTouchEventView extends View {
private Paint paint = new Paint();
private Path path = new Path();
public SingleTouchEventView(Context context, AttributeSet attrs) {
super(context, attrs);
paint.setAntiAlias(true);
paint.setStrokeWidth(6f);
paint.setColor(Color.BLACK);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeJoin(Paint.Join.ROUND);
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawPath(path, paint);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float eventX = event.getX();
float eventY = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
path.moveTo(eventX, eventY);
return true;
case MotionEvent.ACTION_MOVE:
path.lineTo(eventX, eventY);
break;
case MotionEvent.ACTION_UP:
// nothing to do
break;
default:
return false;
}
// Schedules a repaint.
invalidate();
return true;
}
}
You have to call this activity to start paiting:
import android.app.Activity;
import android.os.Bundle;
public class SingleTouchActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new SingleTouchEventView(this, null));
}
}

Android Multi-Touch image view lag

I'm trying to implement a touch responsive image view - like the one in the Gallery application. I've managed to do that, and it works well, except that it is VERY laggy compared to the stock Gallery.
I'm looking for ways to make it smoother.
Here's what I have now:
#SuppressWarnings("unused")
public class ImageDisplayView extends ImageView {
private static final String TAG = "ImageDisplayView";
private static final int MODE_NONE = 0;
private static final int MODE_DRAG = 1;
private static final int MODE_ZOOM = 2;
// Zoom Bounds
private static final float SCALE_MIN = 0.8f;
private static final float SCALE_BOTTOM = 1.0f;
private static final float SCALE_TOP = 10.0f;
private static final float SCALE_MAX = 12.0f;
// Transformation
private Matrix mMatrix = new Matrix();
private Matrix mPreMatrix = new Matrix();
private PointF mPivot = new PointF();
private PointF mNewPivot = new PointF();
private float mDist;
// State
private boolean mInitialScaleDone = false;
private boolean mEnabled = true;
private RectF mBounds = new RectF();
private Float mScale = null;
private float mMode = MODE_NONE;
public ImageDisplayView(Context context) {
super(context);
initialScale();
}
public ImageDisplayView(Context context, AttributeSet attrs) {
super(context, attrs);
initialScale();
}
public ImageDisplayView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initialScale();
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
initialScale();
}
private void initialScale() {
if (!mInitialScaleDone && getDrawable() != null) {
mInitialScaleDone = true;
final Runnable r = new Runnable() {
#Override
public void run() {
// Fit to screen
float scale = calculateFitScreenScale();
mMatrix.reset();
mMatrix.postScale(scale, scale);
setImageMatrix(mMatrix);
// Center
float dx = (getWidth() - mBounds.width()) / 2, dy = (getHeight() - mBounds
.height()) / 2;
mMatrix.postTranslate(dx, dy);
setImageMatrix(mMatrix);
mScale = 1.0f;
}
};
if (getWidth() == 0) {
getViewTreeObserver().addOnGlobalLayoutListener(
new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
r.run();
getViewTreeObserver()
.removeGlobalOnLayoutListener(this);
}
});
} else {
r.run();
}
}
}
#Override
public void setImageMatrix(Matrix matrix) {
super.setImageMatrix(matrix);
mBounds.set(getDrawable().getBounds());
matrix.mapRect(mBounds);
}
#Override
public void setEnabled(boolean enabled) {
mEnabled = enabled;
if (!enabled && mMode != MODE_NONE) {
if (mMode == MODE_DRAG) {
checkLimits(null);
} else {
mPivot.set(getWidth() / 2, getHeight() / 2);
updateScale();
mPreMatrix.set(mMatrix);
checkLimits(null);
}
mMode = MODE_NONE;
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float scale, dx, dy;
if (mEnabled) {
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN:
if (event.getPointerCount() == 1) { // Start mode: drag only.
mMode = MODE_DRAG;
mPivot.set(event.getX(), event.getY());
} else { // Start mode: zoom and drag.
mMode = MODE_ZOOM;
mDist = distance(event);
midPoint(mPivot, event);
}
mPreMatrix.set(mMatrix);
return true;
case MotionEvent.ACTION_UP:
mMode = MODE_NONE;
checkLimits(event);
break;
case MotionEvent.ACTION_POINTER_UP:
if (event.getPointerCount() == 2) {
mMode = MODE_DRAG;
mPivot.set(event.getX(), event.getY());
updateScale();
mPreMatrix.set(mMatrix);
}
return true;
case MotionEvent.ACTION_MOVE:
mMatrix.set(mPreMatrix);
if (mMode == MODE_DRAG) {
dx = event.getX() - mPivot.x;
dy = event.getY() - mPivot.y;
mMatrix.postTranslate(dx, dy);
} else if (mMode == MODE_ZOOM) {
scale = distance(event) / mDist;
midPoint(mNewPivot, event);
dx = mNewPivot.x - mPivot.x;
dy = mNewPivot.y - mPivot.y;
mMatrix.postTranslate(dx, dy);
float postScale = mScale * scale;
if (postScale < SCALE_MIN) {
scale = SCALE_MIN / mScale;
} else if (postScale > SCALE_MAX) {
scale = SCALE_MAX / mScale;
}
mMatrix.postScale(scale, scale, mNewPivot.x, mNewPivot.y);
}
setImageMatrix(mMatrix);
return true;
}
}
return super.onTouchEvent(event);
}
private void updateScale() {
mScale = (mBounds.width() / getDrawable().getIntrinsicWidth())
/ calculateFitScreenScale();
}
#IntendedCaller("onTouchEvent(MotionEvent)")
private void checkLimits(MotionEvent event) {
float scale, dx, dy;
if (mScale < SCALE_BOTTOM) {
scale = SCALE_BOTTOM;
} else if (mScale > SCALE_TOP) {
scale = SCALE_TOP;
} else {
scale = mScale;
}
RectF scaleBounds = new RectF(mBounds); // Use the scale of the image
// to determine drag
// threshold.
scaleBounds.offset(getWidth() / 2 - scaleBounds.centerX(), getHeight()
/ 2 - scaleBounds.centerY());
dx = Math.min(0.0f, Math.max(0.0f, scaleBounds.left) - mBounds.left)
+ Math.max(0.0f, Math.min(getWidth(), scaleBounds.right)
- mBounds.right);
dy = Math.min(0.0f, Math.max(0.0f, scaleBounds.top) - mBounds.top)
+ Math.max(0.0f, Math.min(getHeight(), scaleBounds.bottom)
- mBounds.bottom);
animateTransformation(event, 500, null, scale, dx, dy);
}
public void animateTransformation(MotionEvent event, long duration,
final Runnable callback, final float targetScale, final float dx,
final float dy) {
mPreMatrix.set(mMatrix);
final float scale = targetScale / mScale;
final float px, py;
if (event != null) {
PointF pivot = new PointF();
midPoint(pivot, event);
px = scale > 1.0f ? mBounds.centerX() : dx > 0 ? mBounds.right
: dx < 0 ? mBounds.left : pivot.x;
py = scale > 1.0f ? mBounds.centerY() : dy > 0 ? mBounds.bottom
: dy < 0 ? mBounds.top : pivot.y;
} else {
px = mBounds.centerX();
py = mBounds.centerY();
}
Utils.animate(this, new Animator() {
#Override
public void onAnimationEnd() {
updateScale();
if (callback != null) {
callback.run();
}
}
#Override
public void makeStep(float percent) {
mMatrix.set(mPreMatrix);
float s = 1.0f + percent * (scale - 1.0f);
float tempx = dx * percent, tempy = dy * percent;
mMatrix.postTranslate(tempx, tempy);
mMatrix.postScale(s, s, px + tempx, py + tempy);
setImageMatrix(mMatrix);
}
}, duration);
}
public RectF getBounds() {
return mBounds;
}
public float getScale() {
return mScale;
}
public void scale(float scale, float px, float py) {
mMatrix.set(getImageMatrix());
mMatrix.postScale(scale, scale, px, py);
setImageMatrix(mMatrix);
mScale = scale;
}
public void translate(float dx, float dy) {
mMatrix.set(getImageMatrix());
mMatrix.postTranslate(dx, dy);
setImageMatrix(mMatrix);
}
public void resetAndCenter() {
mMatrix.set(getImageMatrix());
mMatrix.postScale(1 / mScale, 1 / mScale, mBounds.centerX(),
mBounds.centerY());
setImageMatrix(mMatrix);
// Center
float dx = (getWidth() - mBounds.width()) / 2, dy = (getHeight() - mBounds
.height()) / 2;
mMatrix.postTranslate(dx, dy);
setImageMatrix(mMatrix);
updateScale();
}
#Override
public void setImageBitmap(Bitmap bm) {
super.setImageBitmap(bm);
mInitialScaleDone = false;
initialScale();
}
private float distance(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 p, MotionEvent event) {
if (event.getPointerCount() == 1) {
p.set(event.getX(), event.getY());
} else {
p.set((event.getX(1) + event.getX(0)) / 2,
(event.getY(1) + event.getY(0)) / 2);
}
}
private float calculateFitScreenScale() {
RectF r = new RectF(getDrawable().getBounds());
float w = getWidth(), h = getHeight();
if (r.width() > r.height()) {
return w / r.width();
} else if (r.width() == r.height()) {
if (w < h) {
return w / r.width();
} else {
return h / r.height();
}
} else {
return h / r.height();
}
}
}
What can I do in order to make this less laggy? Any help much appreciated.
Have you tried it on an actual device? The emulator in notoriously slow.
Here's something that might help:
Check out the Batching section at the Android Dev Resource page:
http://developer.android.com/reference/android/view/MotionEvent.html
I've noticed that how a device batches together historical points in a continuous motion can differ considerably. This may also differ considerably between devices.
In your code, you only use getX and getY, which takes the most recent event, ignoring all the historical points.
If your device happens to be batching large amounts of historical events together, using only the most recent ones (via getX and getY) might cause lag.
The link suggests how one might consume all the historical points.
You could implement a solution that checks whether too many historical points have been batched together (event.getHistorySize() > x). If the number of historical points are above a threshold of your choosing, make intermediate frame updates based on, say, historySize / 2. Something like that.
Please review this question here
How can I get zoom functionality for images?
theres answer by Mike Ortiz down, implementing Mutli-Touch ImageView

Categories

Resources