I'm scaling the canvas, when I move it, it is going out of the screen.
Screenshot of before translating(i.e., when canvas.onDraw() executes for the first time)
After Move:
I need some condition to say that don't go beyond this point(x-axis - 20).
canvas.save();
int maxX, minX;
minX = /* some condition */;
maxX = /* some condition */;
if (mPosX > maxX)
mPosX = maxX;
if (mPosX < minX)
mPosX = minX;
canvas.translate(mPosX, 0);
canvas.scale(xScaleFactor, yScaleFactor,
px / xScaleFactor + left, py / yScaleFactor + canvas.getClipBounds().top);
paint.setColor(ContextCompat.getColor(getContext(), R.color.green));
canvas.drawRect(20, 20, width, height, paint);
While moving:
#Override
public boolean onTouchEvent(MotionEvent ev) {
mScaleDetector.onTouchEvent(ev);
int eid = ev.getAction();
switch (eid & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
px = ev.getX();
py = ev.getY();
mLastTouchX = px;
mActivePointerId = ev.getPointerId(0);
break;
case MotionEvent.ACTION_MOVE:
if (eid == MotionEvent.ACTION_POINTER_UP || eid == MotionEvent.ACTION_POINTER_DOWN) {
return false;
}
pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK)
>> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
final float x = ev.getX(pointerIndex);
final float dx = x - mLastTouchX;
mPosX += dx;
invalidate();
mLastTouchX = x;
break;
.......
Kindly help to get some condition which will restrict the rectangle from moving away from the screen. So that the left white space is not created. Every time the canvas invalidates, rectangle should start from position 20 of x-axis.
EDIT:
private Matrix m;
m = new Matrix();
m.mapRect(new RectF(20, 0, mPosX, 0));
// in onDraw()
canvas.save();
m.setTranslate(mPosX, 0);
m.setScale(xScaleFactor, yScaleFactor,
(px + canvas.getClipBounds().left)/ xScaleFactor, (py + canvas.getClipBounds().top)/ yScaleFactor);
canvas.concat(m);
paint.setColor(ContextCompat.getColor(getContext(), R.color.green));
canvas.drawRect(20, 20, width, height, paint);
still it is going out
Related
I'm drawing lines on a custom view and added pan and zoom functionality.
The problem is that when I zoom in with two fingers the middle points gets calculated right but when I do matrix.scale(scaleFactor, scaleFactor, midX, midY), the canvas jumps (translates) to the midX and midY which it was before.
Let me get this straight:
I initialize the mid point between my fingers with 0/0. As soon as the second Pointer is on the screen I calculate the mid point and invalidate the onDraw. Then the drawing jumps (translates) to the last known mid point and starts to zoom in.
I don't want the drawing to be translated to the mid point rather than just zoom to the selected mid point.
Here are the relevant code snippets:
onDraw method
private float startX = 0f;
private float startY = 0f;
private float translateX;
private float translateY;
private float previousTranslateX = 0f;
private float previousTranslateY = 0f;
private float midX = 0f;
private float midY = 0f;
...
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
cx = canvas.getWidth();
cy = canvas.getHeight();
mat.reset();
canvas.save();
int count = 0;
mat.postScale(scaleFactor, -scaleFactor, midX, midY);
mat.postTranslate(translateX, translateY);
canvas.setMatrix(mat);
// draw stuff here...
canvas.restore();
}
onTouch method
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
mode = DRAG;
startX = event.getX() - previousTranslateX;
startY = event.getY() - previousTranslateY;
break;
case MotionEvent.ACTION_MOVE:
if (event.getPointerCount() > 1) {
mode = ZOOM;
} else {
translateX = event.getX() - startX;
translateY = event.getY() - startY;
}
break;
case MotionEvent.ACTION_POINTER_DOWN:
mode = NONE;
getMidPoint(event);
break;
case MotionEvent.ACTION_UP:
mode = NONE;
previousTranslateX = translateX;
previousTranslateY = translateY;
break;
case MotionEvent.ACTION_POINTER_UP:
mode = DRAG;
previousTranslateX = translateX;
previousTranslateY = translateY;
break;
}
detector.onTouchEvent(event);
if ((mode == DRAG) || mode == ZOOM) {
invalidate();
}
return true;
}
calculation of mid point
private void getMidPoint(MotionEvent event) {
//get offset screensize -> canvas
int offX = sx-cx;
int offY = sy-cy;
//get finger coordinates relative to offset
f1x = event.getX(0)+offX;
f1y = event.getY(0)+offY;
f2x = event.getX(1)+offX;
f2y = event.getY(1)+offY;
midX = (f1x + f2x)/2;
midY = (f1y + f2y)/2;
//because my points are in a local coordinate system the
screen coordinates need to be mapped to current canvas matrix
Matrix m = new Matrix(mat);
m.invert(m);
float[] touch = new float[] { midX, midY };
m.mapPoints(touch);
midX = touch[0];
midY = touch[1];
}
Here are some pictures:
This is when the activity starts. The red dot marks the 0/0 position of the initialized mid point
As soon as a put my fingers where the blue dots are and start zooming:
this will be the result. This happens as soon as I start to zoom.
I'd really appreciate if someone has an answer for me! Thanks in advance.
I have already searched alot around here but haven't found a solution yet. So the thing is , I have a image 3000*3000 px, I set it to scale type matrix. Now I have only the left corner showing of the image. Now I don't want people to zoom in at this stage, only zoom out to a maximum of 'x' (Still have to see how much).
It's the imageview "kaart" that has to be zoomed.
question : How to let people only zoom out in the beginning and don't let them pass x ?and afterwards, don't let them zoom in more than the original size
i've tried with negative values , but that didn't work
Here is my code:
// These matrices will be used to move and zoom image
Matrix matrix = new Matrix();
Matrix savedMatrix = new Matrix();
// max and min zoom
//private static final float MIN_ZOOM = 1.0f;
//private static final float MAX_ZOOM = 5.0f;
//scale = Math.max(MIN_ZOOM, Math.min(scale, MAX_ZOOM));
// 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 start = new PointF();
PointF mid = new PointF();
float oldDist = 1f;
String savedItemClicked;
ImageView view;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.kaart);
view = (ImageView) findViewById(R.id.kaart);
view.setOnTouchListener(this);
}
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
ImageView view = (ImageView) v;
dumpEvent(event);
// Handle touch events here...
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_POINTER_DOWN:
oldDist = spacing(event);
//Log.d(TAG, "oldDist=" + oldDist);
if (oldDist > 10f) {
savedMatrix.set(matrix);
midPoint(mid, event);
mode = ZOOM;
//Log.d(TAG, "mode=ZOOM");
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
// Log.d(TAG, "mode=NONE");
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 > 10f) {
matrix.set(savedMatrix);
float scale = newDist / oldDist;
matrix.postScale(scale, scale, mid.x, mid.y);
}
}
break;
}
limitZoom(matrix);
limitDrag(matrix);
view.setImageMatrix(matrix);
return true;
}
#SuppressWarnings("deprecation")
private void dumpEvent(MotionEvent event) {
String names[] = { "DOWN", "UP", "MOVE", "CANCEL", "OUTSIDE",
"POINTER_DOWN", "POINTER_UP", "7?", "8?", "9?" };
StringBuilder sb = new StringBuilder();
int action = event.getAction();
int actionCode = action & MotionEvent.ACTION_MASK;
sb.append("event ACTION_").append(names[actionCode]);
if (actionCode == MotionEvent.ACTION_POINTER_DOWN
|| actionCode == MotionEvent.ACTION_POINTER_UP) {
sb.append("(pid ").append(
action >> MotionEvent.ACTION_POINTER_ID_SHIFT);
sb.append(")");
}
sb.append("[");
for (int i = 0; i < event.getPointerCount(); i++) {
sb.append("#").append(i);
sb.append("(pid ").append(event.getPointerId(i));
sb.append(")=").append((int) event.getX(i));
sb.append(",").append((int) event.getY(i));
if (i + 1 < event.getPointerCount())
sb.append(";");
}
sb.append("]");
// Log.d(TAG, sb.toString());
}
/** 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);
return FloatMath.sqrt(x * x + y * y);
}
/** 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);
}
}
Hope someone can help me. I would really apreciate it.
EDIT
I have added 2 functions i found somewhere.
private void limitZoom(Matrix m) {
float[] values = new float[9];
m.getValues(values);
float scaleX = values[Matrix.MSCALE_X];
float scaleY = values[Matrix.MSCALE_Y];
if(scaleX > MAX_ZOOM) {
scaleX = MAX_ZOOM;
} else if(scaleX < MIN_ZOOM) {
scaleX = MIN_ZOOM;
}
if(scaleY > MAX_ZOOM) {
scaleY = MAX_ZOOM;
} else if(scaleY < MIN_ZOOM) {
scaleY = MIN_ZOOM;
}
values[Matrix.MSCALE_X] = scaleX;
values[Matrix.MSCALE_Y] = scaleY;
m.setValues(values);
}
and
private void limitDrag(Matrix m) {
float[] values = new float[9];
m.getValues(values);
float transX = values[Matrix.MTRANS_X];
float transY = values[Matrix.MTRANS_Y];
float scaleX = values[Matrix.MSCALE_X];
float scaleY = values[Matrix.MSCALE_Y];
ImageView iv = (ImageView)findViewById(R.id.kaart);
Rect bounds = iv.getDrawable().getBounds();
int viewWidth = getResources().getDisplayMetrics().widthPixels;
int viewHeight = getResources().getDisplayMetrics().heightPixels;
int width = bounds.right - bounds.left;
int height = bounds.bottom - bounds.top;
float minX = (-width + 20) * scaleX;
float minY = (-height + 20) * scaleY;
if(transX > (viewWidth - 20)) {
transX = viewWidth - 20;
} else if(transX < minX) {
transX = minX;
}
if(transY > (viewHeight - 80)) {
transY = viewHeight - 80;
} else if(transY < minY) {
transY = minY;
}
values[Matrix.MTRANS_X] = transX;
values[Matrix.MTRANS_Y] = transY;
m.setValues(values);
}
I have to call these functions right after the switch case and just before is set the imagematrix on my view. (I have added this to my previous code here above)
maybe this isn't the best solution , but it works .
If I understand your code, you keep saving the matrix as a way to remember what was the state of the zoom and scroll (which could be done by one matrix alone, but maybe you're doing other manipulations).
This way, every action effects are relative to the last state, and it's difficult to set an absolute limit to the zoom (and scroll too): to get their absolute values, you'd have to call matrix.getValues() and pick the values from the array it returns.
Try instead saving the current x-scroll, y-scroll and zoom, and at every action check if their updated values (that now remain absolute) would be inside your limits; if so actually update them, then reset the matrix and set the new scroll/zoom values.
(also, consider the use of GestureDetector and ScaleGestureDetector)
I'm developing an application in which I'm pasting images, doing drawing and painting on canvas. This app can also Scale up/down the canvas or drag it to different location.
My problem is: I can't get the correct canvas coordinates after scaling or dragging the canvas. I want to draw finger paint after the canvas is scaled or dragged but unable to retrieve the right place where i've touched..:(
Also I'm new bee. Here is the code.
#Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.save();
//canvas.translate(mPosX, mPosY);
canvas.scale(mScaleFactor, mScaleFactor, super.getWidth() * 0.5f,
super.getHeight() * 0.5f);
mIcon.draw(canvas);
for (Path path : listPath) {
canvas.drawPath(path, paint);
}
canvas.restore();
}
public TouchExampleView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
// Let the ScaleGestureDetector inspect all events.
mScaleDetector.onTouchEvent(ev);
final int action = ev.getAction();
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN: {
final float x = ev.getX();
final float y = ev.getY();
mLastTouchX = x;
mLastTouchY = y;
mActivePointerId = ev.getPointerId(0);
break;
}
case MotionEvent.ACTION_MOVE: {
final int pointerIndex = ev.findPointerIndex(mActivePointerId);
final float x = ev.getX(pointerIndex);
final float y = ev.getY(pointerIndex);
// Only move if the ScaleGestureDetector isn't processing a gesture.
if (!mScaleDetector.isInProgress()) {
final float dx = x - mLastTouchX;
final float dy = y - mLastTouchY;
mPosX += dx;
mPosY += dy;
invalidate();
}
mLastTouchX = x;
mLastTouchY = y;
break;
}
case MotionEvent.ACTION_UP: {
mActivePointerId = INVALID_POINTER_ID;
break;
}
case MotionEvent.ACTION_CANCEL: {
mActivePointerId = INVALID_POINTER_ID;
break;
}
case MotionEvent.ACTION_POINTER_UP: {
final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
final int pointerId = ev.getPointerId(pointerIndex);
if (pointerId == mActivePointerId) {
// This was our active pointer going up. Choose a new
// active pointer and adjust accordingly.
final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
mLastTouchX = ev.getX(newPointerIndex);
mLastTouchY = ev.getY(newPointerIndex);
mActivePointerId = ev.getPointerId(newPointerIndex);
}
break;
}
}
float objectNewX,objectNewY;
if (mScaleFactor >= 1) {
objectNewX = ev.getX() + (ev.getX() - super.getWidth() * 0.5f) * (mScaleFactor - 1);
objectNewY = ev.getY() + (ev.getY() - super.getHeight() * 0.5f) * (mScaleFactor - 1);
} else {
objectNewX = ev.getX() - (ev.getX() - super.getWidth() * 0.5f) * (1 - mScaleFactor);
objectNewY = ev.getY() - (ev.getY() - super.getHeight() * 0.5f) * (1 - mScaleFactor);
}
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
path = new Path();
path.moveTo(objectNewX,objectNewY);
path.lineTo(objectNewX,objectNewY);
} else if (ev.getAction() == MotionEvent.ACTION_MOVE) {
path.lineTo(objectNewX,objectNewY);
listPath.add(path);
} else if (ev.getAction() == MotionEvent.ACTION_UP) {
path.lineTo(objectNewX,objectNewY);
listPath.add(path);
}
return true;
}
private class ScaleListener extends
ScaleGestureDetector.SimpleOnScaleGestureListener {
#Override
public boolean onScale(ScaleGestureDetector detector) {
mScaleFactor *= detector.getScaleFactor();
// Don't let the object get too small or too large.
mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 5.0f));
invalidate();
return true;
}
}
Done it finally by myself.
Draw everything by applying this formula to (px,py) coordinates:
float px = ev.getX() / mScaleFactor + rect.left;
float py = ev.getY() / mScaleFactor + rect.top;
rect = canvas.getClipBounds();
//Get them in on Draw function and apply above formula before drawing
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
clipBounds_canvas = canvas.getClipBounds();
/////Do whatever you want to do..!!!
};
#Override
public boolean onTouchEvent(MotionEvent ev) {
int x = ev.getX() / zoomFactor + clipBounds_canvas.left;
int y = ev.getY() / zoomFactor + clipBounds_canvas.top;
//Use the above two values insted of ev.getX() and ev.getY();
}
Hope this will help.
Can anybody tell me how to scroll a bitmap with two fingers, because in my app I am using one finger to paint. Since I want to paint an entire image (it may be larger than the screen) scrolling with two fingers would be convenient?
private class Img extends View {
private Bitmap bmp;
private Rect imgRect, scrollRect;
private float prevX, prevY;
private int newX, newY;
public Img(Context context) {
super(context);
bmp = BitmapFactory.decodeResource(getResources(),
R.drawable.screen);
imgRect = new Rect(0, 0, width, height);
scrollRect = new Rect(0, 0, width, height);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE: {
int numPointers = event.getPointerCount();
if (numPointers > 1) {
float currX = event.getRawX();
float deltaX = -(currX - prevX);
newX += deltaX;
float currY = event.getRawY();
float deltaY = -(currY - prevY);
newY += deltaY;
if (newX < 0)
newX = 0;
if (newY < 0)
newY = 0;
if (newX > bmp.getWidth() - width)
newX = bmp.getWidth() - width;
if (newY > bmp.getHeight() - height)
newY = bmp.getHeight() - height;
scrollRect.set(newX, newY, newX + width, newY + height);
invalidate();
prevX = currX;
prevY = currY;
}
break;
}
case MotionEvent.ACTION_DOWN: {
prevX = event.getRawX();
prevY = event.getRawY();
break;
}
}
return true;
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(bmp, scrollRect, imgRect, new Paint());
}
}
Here Img class represents the View with a large bitmap, which displays its currently visible rectangle. int numPointers = event.getPointerCount();
if (numPointers > 1) { - and here you get number of fingers, that touch the screen. So if it is greater than 1, large image will be scrolled, otherwise, you can implement your paint logic.
How can I write text on an image and then save it in Android?
Basically I want to let user write something on the images which my camera app will click for them. I can write and show it to them using the onDraw method on the preview of the camera. But after the user has clicked the picture I want to write the text over the picture and then save it.
You can put an EditText and write into it, and after writing, you first convert it to Bitmap like:
Bitmap bmp = Bitmap.createBitmap(mEditText.getDrawingCache());
Now you can add created image bmp to your original image like this:
Call: Bitmap combined = combineImages(bgBitmap,bmp);
public Bitmap combineImages(Bitmap background, Bitmap foreground) {
int width = 0, height = 0;
Bitmap cs;
width = getWindowManager().getDefaultDisplay().getWidth();
height = getWindowManager().getDefaultDisplay().getHeight();
cs = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas comboImage = new Canvas(cs);
background = Bitmap.createScaledBitmap(background, width, height, true);
comboImage.drawBitmap(background, 0, 0, null);
comboImage.drawBitmap(foreground, matrix, null);
return cs;
}
You have to implement a canvas that allows the user to draw on it and then set the background of that canvas to that particular image. This is just a guess but its somewhere there abouts.
Lets help you..
First of all you must have to use canvas for drawing. Make a custom view which extends ImageView. Here is the helping code for onDraw function..:
#Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
mIcon.setBounds(0, 0, mIcon.getMinimumWidth(),
mIcon.getMinimumHeight());
canvas.translate(mPosX, mPosY);
canvas.scale(mScaleFactor, mScaleFactor, canvas.getWidth() * 0.5f,
canvas.getWidth() * 0.5f);
mIcon.draw(canvas);
rect = canvas.getClipBounds();
for (Path path : listPath) {
canvas.drawPath(path, paint);
}
}
Now for onTouch:
#Override
public boolean onTouchEvent(MotionEvent ev) {
// Let the ScaleGestureDetector inspect all events.
mScaleDetector.onTouchEvent(ev);
final int action = ev.getAction();
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN: {
if (drawing) {
startPoint = new Point((int) ev.getX(), (int) ev.getY());
path = new Path();
float x = ev.getX() / mScaleFactor + rect.left;
float y = ev.getY() / mScaleFactor + rect.top;
path.moveTo(x, y);
path.lineTo(x, y);
mLastTouchX_1 = x;
mLastTouchY_1 = y;
}
else {
final float x = ev.getX();
final float y = ev.getY();
mLastTouchX = x;
mLastTouchY = y;
mActivePointerId = ev.getPointerId(0);
}
break;
}
case MotionEvent.ACTION_MOVE: {
if (drawing) {
float x = ev.getX() / mScaleFactor + rect.left;
float y = ev.getY() / mScaleFactor + rect.top;
path.moveTo(mLastTouchX_1, mLastTouchY_1);
path.lineTo(x, y);
mLastTouchX_1 = x;
mLastTouchY_1 = y;
}
else {
final int pointerIndex = ev
.findPointerIndex(mActivePointerId);
final float x = ev.getX(pointerIndex);
final float y = ev.getY(pointerIndex);
// Only move if the ScaleGestureDetector isn't processing a
// gesture.
if (!mScaleDetector.isInProgress()) {
final float dx = x - mLastTouchX;
final float dy = y - mLastTouchY;
mPosX += dx;
mPosY += dy;
invalidate();
}
mLastTouchX = x;
mLastTouchY = y;
}
break;
}
case MotionEvent.ACTION_UP: {
path_helper_1 = new Path();
path_helper_2 = new Path();
endPoint = new Point((int) ev.getX(), (int) ev.getY());
int left, top, right, bottom;
left = endPoint.x - 10;
top = endPoint.y - 10;
right = endPoint.x + ((endPoint.y / 2));
bottom = endPoint.x + ((endPoint.y / 2));
float dx, dy;
dx = endPoint.x - startPoint.x;
dy = endPoint.y - startPoint.y;
dx = dx * -1;
dy = dy * -1;
// dx = dy = 100;
double cos = 0.866 * .1;
double sin = 0.500 * .1;
PointF end1 = new PointF((float) (endPoint.x + (dx * cos + dy
* -sin)), (float) (endPoint.y + (dx * sin + dy * cos)));
PointF end2 = new PointF((float) (endPoint.x + (dx * cos + dy
* sin)), (float) (endPoint.y + (dx * -sin + dy * cos)));
// path.moveTo(endPoint.x, endPoint.y);
//
// path.lineTo(endPoint.x, endPoint.y);
//
// path.lineTo(end1.x, end1.y);
//
// path.moveTo(endPoint.x, endPoint.y);
//
// path.lineTo(end2.x, end2.y);
//
//
// listPath.add(path);
mActivePointerId = INVALID_POINTER_ID;
break;
}
case MotionEvent.ACTION_CANCEL: {
mActivePointerId = INVALID_POINTER_ID;
break;
}
case MotionEvent.ACTION_POINTER_UP: {
final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
final int pointerId = ev.getPointerId(pointerIndex);
if (pointerId == mActivePointerId) {
// This was our active pointer going up. Choose a new
// active pointer and adjust accordingly.
final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
mLastTouchX = ev.getX(newPointerIndex);
mLastTouchY = ev.getY(newPointerIndex);
mActivePointerId = ev.getPointerId(newPointerIndex);
}
break;
}
}
invalidate();
return true;
}
Also make a private class if you want to implement zooming functionality like this:
private class ScaleListener extends
ScaleGestureDetector.SimpleOnScaleGestureListener {
#Override
public boolean onScale(ScaleGestureDetector detector) {
if (zoom) {
mScaleFactor *= detector.getScaleFactor();
// Don't let the object get too small or too large.
mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 5.0f));
}
invalidate();
return true;
}
}
}
Take the idea from above code and make changes according to your requirements.
NOTE Above code implements Drawing And Zooming functionality. If you want to add text over images then like Path drawing you can also draw text on canvas using canvas.drawText. Make an arraylist if you want multiple text overs image.
Add text on bitmap :
public Bitmap drawTextToBitmap(Context gContext,
int gResId,
String gText) {
Resources resources = gContext.getResources();
float scale = resources.getDisplayMetrics().density;
Bitmap bitmap =
BitmapFactory.decodeResource(resources, gResId);
android.graphics.Bitmap.Config bitmapConfig =
bitmap.getConfig();
// set default bitmap config if none
if(bitmapConfig == null) {
bitmapConfig = android.graphics.Bitmap.Config.ARGB_8888;
}
// resource bitmaps are imutable,
// so we need to convert it to mutable one
bitmap = bitmap.copy(bitmapConfig, true);
Canvas canvas = new Canvas(bitmap);
// new antialised Paint
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
// text color - #3D3D3D
paint.setColor(Color.rgb(61, 61, 61));
// text size in pixels
paint.setTextSize((int) (14 * scale));
// text shadow
paint.setShadowLayer(1f, 0f, 1f, Color.WHITE);
// draw text to the Canvas center
Rect bounds = new Rect();
paint.getTextBounds(gText, 0, gText.length(), bounds);
int x = (bitmap.getWidth() - bounds.width())/2;
int y = (bitmap.getHeight() + bounds.height())/2;
canvas.drawText(gText, x, y, paint);
return bitmap;
}
Source : http://www.skoumal.net/en/android-how-draw-text-bitmap/
Add multi line text on bitmap :
public Bitmap drawMultilineTextToBitmap(Context gContext,
int gResId,
String gText) {
// prepare canvas
Resources resources = gContext.getResources();
float scale = resources.getDisplayMetrics().density;
Bitmap bitmap = BitmapFactory.decodeResource(resources, gResId);
android.graphics.Bitmap.Config bitmapConfig = bitmap.getConfig();
// set default bitmap config if none
if(bitmapConfig == null) {
bitmapConfig = android.graphics.Bitmap.Config.ARGB_8888;
}
// resource bitmaps are imutable,
// so we need to convert it to mutable one
bitmap = bitmap.copy(bitmapConfig, true);
Canvas canvas = new Canvas(bitmap);
// new antialiased Paint
TextPaint paint=new TextPaint(Paint.ANTI_ALIAS_FLAG);
// text color - #3D3D3D
paint.setColor(Color.rgb(61, 61, 61));
// text size in pixels
paint.setTextSize((int) (14 * scale));
// text shadow
paint.setShadowLayer(1f, 0f, 1f, Color.WHITE);
// set text width to canvas width minus 16dp padding
int textWidth = canvas.getWidth() - (int) (16 * scale);
// init StaticLayout for text
StaticLayout textLayout = new StaticLayout(
gText, paint, textWidth, Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false);
// get height of multiline text
int textHeight = textLayout.getHeight();
// get position of text's top left corner
float x = (bitmap.getWidth() - textWidth)/2;
float y = (bitmap.getHeight() - textHeight)/2;
// draw text to the Canvas center
canvas.save();
canvas.translate(x, y);
textLayout.draw(canvas);
canvas.restore();
return bitmap;
}
Source : http://www.skoumal.net/en/android-drawing-multiline-text-on-bitmap/