i have relative parent layout and adding custom textview dynamically into it. when i drag(move) and scale my current textview it get weird jumps continuously in both pointer index. how can i solve this issue?
my custom textview as given below:
public class VideoTextView extends TextView implements View.OnTouchListener {
private final String TAG = this.getClass().getSimpleName();
private Context context;
private Matrix matrix = new Matrix();
private Matrix savedMatrix = new Matrix();
private PointF start = new PointF();
private PointF mid = new PointF();
private float[] matrixValues = new float[9];
private Paint paint;
private Paint linePaint;
private VideoTextMovement videoTextMovement;
private OperationListener operationListener;
private int widthView, heightView;
private boolean isInEdit;
public VideoTextView(Context context, int widthView, int heightView) {
super(context);
this.context = context;
this.widthView = widthView;
this.heightView = heightView;
videoTextMovement = (VideoTextMovement) context;
init();
}
public void updateViewWidthHeight(int widthView, int heightView) {
this.widthView = widthView;
this.heightView = heightView;
}
private void init() {
paint = new Paint();
paint.setTextSize(8);
paint.setColor(context.getResources().getColor(R.color.white));
linePaint = new Paint();
linePaint.setColor(getResources().getColor(R.color.colorPrimary));
linePaint.setAntiAlias(true);
linePaint.setDither(true);
linePaint.setStyle(Paint.Style.STROKE);
linePaint.setStrokeWidth(3.0f);
// setTextSize(8f);
setTextColor(getResources().getColor(R.color.colorAccent));
setOnTouchListener(this);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int textWidth = getMeasuredWidth();
int textHeight = getMeasuredHeight();
int origWidth = textWidth;
int origHeight = textHeight;
matrix.getValues(matrixValues);
canvas.save();
canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG & Paint.FILTER_BITMAP_FLAG));
float transX = matrixValues[Matrix.MTRANS_X];
float transY = matrixValues[Matrix.MTRANS_Y];
float scaleX = matrixValues[Matrix.MSCALE_X];
float scaleY = matrixValues[Matrix.MSCALE_Y];
float maxScale = widthView / textWidth;
Log.e(TAG + " ====", "matrix scale " + scaleX + " " + scaleY + " max scale " + maxScale);
scaleX = Math.max(0.5f, Math.min(scaleX, maxScale));
scaleY = Math.max(0.5f, Math.min(scaleY, maxScale));
if (scaleX > 1.0f) {
textWidth = (int) (textWidth + (textWidth * (scaleX - 1.0f)));
} else if (scaleX < 1.0f) {
textWidth = (int) (textWidth * scaleX);
}
if (scaleY > 1.0f) {
textHeight = (int) (textHeight + (textHeight * (scaleY - 1.0f)));
} else if (scaleY < 1.0f) {
textHeight = (int) (textHeight * scaleY);
}
Log.e(TAG + " ====", "original Tx-Ty " + transX + " - " + transY);
if (transX < 0) {
transX = 0;
}
if (transY < 0) {
transY = 0;
}
if (transX > (widthView - textWidth)) {
transX = widthView - textWidth;
}
if (transY > (heightView - textHeight)) {
transY = heightView - textHeight;
}
Log.e(TAG + " ====", "original w-h " + origWidth + " - " + origHeight + " " + " increased w-h " + textWidth + " - " + textHeight);
Log.e(TAG + " ====", "diff w-h " + Math.abs(origWidth - textWidth) + " - " + Math.abs(origHeight - textHeight));
matrixValues[Matrix.MTRANS_X] = transX;
matrixValues[Matrix.MTRANS_Y] = transY;
matrixValues[Matrix.MSCALE_X] = scaleX;
matrixValues[Matrix.MSCALE_Y] = scaleY;
matrix.setValues(matrixValues);
setX(transX + (textWidth - origWidth) / 2);
setY(transY + (textHeight - origHeight) / 2);
setScaleX(scaleX);
setScaleY(scaleY);
// setPivotX(mid.x);
// setPivotY(mid.y);
Log.e(TAG + " ====", "translateFactor " + transX + " - " + transY + " scaleFactor " + scaleX + " - " + scaleY);
videoTextMovement.translateText(getId(), transX, transY, textWidth, textHeight, getTextSize());
if (isInEdit) {
canvas.drawLine(0, origHeight, origWidth, origHeight, linePaint);
}
canvas.restore();
Log.e(TAG + " ===", TAG + " onDraw");
}
public void midPoint(MotionEvent event) {
float x = event.getX(0) + event.getX(1);
float y = event.getY(0) + event.getY(1);
Log.e(TAG + " ====", "mid point x-y " + (x / 2) + " " + (y / 2));
mid.set(x / 2, y / 2);
}
private float spacing(MotionEvent event) {
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
Log.e(TAG + " ====", "spacing x-y " + (x * x + y * y));
return (float) Math.sqrt(x * x + y * y);
}
float rawX0;
float rawY0;
float rawX1;
float rawY1;
private void getOriginalLocation(MotionEvent event) {
int[] location = {0, 0};
getLocationOnScreen(location);
rawX0 = event.getX(0) + location[0];
rawY0 = event.getY(0) + location[1];
float x = event.getRawX();
float y = event.getRawY();
Log.e(TAG + " ===", "actual raw co. " + x + "-" + y);
Log.e(TAG + " ===", "custom raw co. " + rawX0 + "-" + rawY0);
rawX1 = event.getX(1) + location[0];
rawY1 = event.getY(1) + location[1];
}
private float getRawX(MotionEvent event, int pointerIndex) {
float offset = event.getRawX() - event.getX();
return event.getX(pointerIndex) + offset;
}
private float getRawY(MotionEvent event, int pointerIndex) {
float offset = event.getRawY() - event.getY();
return event.getY(pointerIndex) + offset;
}
public void setInEdit(boolean isInEdit) {
this.isInEdit = isInEdit;
invalidate();
}
public void setOperationListener(OperationListener operationListener) {
this.operationListener = operationListener;
}
private float oldDist;
private final int NONE = -1;
private final int DRAG = 1;
private final int ZOOM = 2;
private int mode = NONE;
#Override
public boolean onTouch(View view, MotionEvent event) {
float downX, downY;
float moveX, moveY;
switch (event.getAction() & event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
downX = event.getX();
downY = event.getY();
savedMatrix.set(matrix);
start.set(downX, downY);
mode = DRAG;
Log.e(TAG + " ===", "Action down X=" + downX + " Y=" + downY);
break;
case MotionEvent.ACTION_POINTER_DOWN:
oldDist = spacing(event);
savedMatrix.set(matrix);
midPoint(event);
mode = ZOOM;
Log.e(TAG + " ===", "Pointer down");
break;
case MotionEvent.ACTION_MOVE:
if (mode == DRAG) {
moveX = event.getX();
moveY = event.getY();
float mdX = moveX - start.x;
float mdY = moveY - start.y;
matrix.set(savedMatrix);
matrix.postTranslate(mdX, mdY);
invalidate();
Log.e(TAG + " ===", "draging");
Log.e(TAG + " ===", "draging x-y rawx-rawy " + event.getX() + "-" + event.getY() + " " + event.getRawX() + "-" + event.getRawY());
} else if (mode == ZOOM) {
float newDist = spacing(event);
float scale = (newDist / oldDist);
matrix.set(savedMatrix);
Log.e(TAG + " ====", "Zoom scale " + scale);
matrix.postScale(scale, scale/*, mid.x, mid.y*/);
invalidate();
Log.e(TAG + " ===", "scaling");
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
Log.e(TAG + " ===", "Action up, Pointer up");
break;
}
if (operationListener != null) {
operationListener.onEdit(this);
}
return true;
}
public interface OperationListener {
void onEdit(VideoTextView videoTextview);
}
}
I have added my touch listener and all necessary functions that i have used to perform drag and scale event in my code to solve this issue, but every time i get fail to solve.
My Layout XML:
<FrameLayout
android:id="#+id/videoEditorParent"
android:layout_width="match_parent"
android:layout_height="400dp">
<RelativeLayout
android:id="#+id/vidEditorWrapper"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="#color/colorAccent">
<VideoView
android:id="#+id/vidEditor"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
</FrameLayout>
can somebody help to solve this kind to problem?
Thanks.
Related
I am trying to make real time application based on canvas writing here multiple device will be connected with this application if i write something on canvas it should reflect on other devices which are connected with this app here my issue is i am able to write on canvas and its also writes smooth but when it comes to receiving end its getting disjoint segment not clear path visible on canvas.
I am using thread using moveTo() and quadTo()to and receiving points from server
here images for reference
Source writing
Receiving end
Here is my code which i am trying
onDraw method
#Override
protected void onDraw(final Canvas canvas) {
normal_canvas_draw=true;
bckimage = getBackground();
String col = "#333333".substring(1);
col = col.toLowerCase();
col = "#ff" + col;
mc.setcanvas(canvas);
paint1.setAntiAlias(true);
paint1.setDither(true);
paint1.setStyle(Paint.Style.STROKE);
paint1.setStrokeJoin(Paint.Join.ROUND);
paint1.setStrokeCap(Paint.Cap.ROUND);
paint1.setPathEffect(new CornerPathEffect(30) ); // set the path effect when they join.
paint.setDither(true); // set the dither to true
paint.setStyle(Paint.Style.STROKE); // set to STOKE
paint.setStrokeJoin(Paint.Join.ROUND); // set the join to round you want
paint.setStrokeCap(Paint.Cap.ROUND); // set the paint cap to round too
paint.setPathEffect(new CornerPathEffect(30) ); // set the path effect when they join.
paint.setAntiAlias(true);
mCanvas.drawPath(path, paint);
mCanvas.drawPath(path1, paint1);
/*
for(Path p :paths)
{
mCanvas.drawPath(p, paint1);
}*/
//mCanvas.drawPath(path1, paint1);
//s = paths.size();
s = type.size();
Log.d("BLOCK", s + " , " + leftval.size());
int j = 0, k = 0;
canvas.drawBitmap(img, 0, 0, null);
canvas.drawText(mc.getDisplaymsg(), mCanvas.getWidth()-200, 25, painttext);
r = new Rect(10, 600, 100, 650);
}
onTouchEvent
#Override
public boolean onTouchEvent(MotionEvent event) {
if (mIsScrolling)
sv.requestDisallowInterceptTouchEvent(false);
else
sv.requestDisallowInterceptTouchEvent(true);
float eventX = event.getX();
float eventY = event.getY();
boolean touchcaptured = false;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
path.reset();
// path.moveTo(eventX, eventY);
boolean l = r.contains((int) event.getX(), (int) event.getY());
if (markerMode)
{
isEraserDown="false";
isPenDown="false";
isMarkerDown="true";
path.moveTo(eventX,eventY);
startX=eventX/scalefactor;
startY=eventY/scalefactor;
mX=eventX;
mY=eventY;
MainActivity.super.loadUrl("javascript:eraserfunction(" + eventX / scalefactor + "," + eventY / scalefactor + "," + mc.getdrawAttributes1() + ")");
}
else if (eraseMode)
{
isEraserDown="true";
isPenDown="false";
isMarkerDown="false";
System.out.println("--Eraserfromtouch");
path.moveTo(eventX,eventY);
startX=eventX/scalefactor;
startY=eventY/scalefactor;
mX=eventX;
mY=eventY;
MainActivity.super.loadUrl("javascript:eraserfunction(" + eventX / scalefactor + "," + eventY / scalefactor + "," + mc.getdrawAttributes1() + ")");
}
else if (blockerase) {
// left=(int) event.getX();
// right=left+1;
// top=(int) event.getY();
// bottom=top+1;
rx = (int) event.getX();
ry = (int) event.getY();
}
/*------------------- Pendown when we touch on mobile screen------*/
else if (penmode) {
isPenDown="true";
isEraserDown="false";
isMarkerDown="false";
System.out.println("---pen-down---"+eventX+","+eventY);
int historySize = event.getHistorySize();
if(isPenDown=="true")
{
path.moveTo(eventX,eventY);
mX = eventX;
mY = eventY;
startX=eventX/scalefactor;
startY=eventY/scalefactor;
mc.setXY(eventX / scalefactor, eventY / scalefactor);
MainActivity.super.loadUrl("javascript:penDown(0,0,'pen')");
}
else
{
}
// System.out.println(" Lcal x"+eventX+" y"+eventY+" x2"+eventX+" y2"+eventY);
} else if (rectanglemode) {
rx = (int) event.getX();
ry = (int) event.getY();
} else if (linemode) {
rx = (int) event.getX();
ry = (int) event.getY();
} else if (circlemode) {
cx = (int) event.getX();
cy = (int) event.getY();
MainActivity.super.loadUrl("javascript:circleDown(" + cx / scalefactor + "," + cy / scalefactor + ")");
} else if (textmode) {
cx = (int) event.getX();
cy = (int) event.getY();
//MainActivity.super.loadUrl("javascript:drawtext(" +cx + "," + cy+","+"Hello World"+")");
}
//invalidate();
break;
case MotionEvent.ACTION_MOVE:
if (markerMode) {
if (isMarkerDown.equals("true")) {
System.out.println("Marker Move");
Log.d("MARKER", "Hi im marker");
String col = mc.getdrawAttributes().substring(1);
col = col.toLowerCase();
col = "#ff" + col;
int coll = Color.parseColor(col);
paint.setColor(coll);
paint.setAlpha(10);
paint.setStrokeWidth(20);
if (bckimage == null) {
} else {
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.XOR));
}
MainActivity.super.loadUrl("javascript:marker1(" + eventX / scalefactor + "," + eventY / scalefactor + ")");
}
else{
}
path.quadTo(mX,mY,(mX+event.getX())/2,(mY+event.getY())/2);
mX=event.getX();
mY=event.getY();
}
else if (eraseMode)
{
if(isEraserDown=="true")
{
System.out.println("--Eraserfromtouch--MOVE");
System.out.println("Marker Move");
Log.d("Eraser", "Im eraser");
String thh = mc.getdrawAttributes1();
float f = Float.parseFloat(thh);
paint.setStrokeWidth(f);
if (bckimage == null) {
paint.setColor(Color.WHITE); //Toast.makeText(getContext(),"ERASE",Toast.LENGTH_LONG).show();
} else {
// setLayerType(View.LAYER_TYPE_SOFTWARE, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
MainActivity.super.loadUrl("javascript:eraserfunction1(" + eventX / scalefactor + "," + eventY / scalefactor + "," + mc.getdrawAttributes1() + ")");
}
path.quadTo(mX,mY,(mX+event.getX())/2,(mY+event.getY())/2);
mX=event.getX();
mY=event.getY();
}
else
{
}
}
else if (blockerase) {
qx = (int) event.getX();
qy = (int) event.getY();
}
/*------------------Pen move on the screen following by finger-------------*/
else if (penmode) {
if(isPenDown=="true")
{
String thh1 = mc.getdrawAttributes1();
float width = Float.parseFloat(thh1);
paint.setStrokeWidth(width);
paint.setColor(color);
paint.setDither(true); // set the dither to true
paint.setStyle(Paint.Style.STROKE); // set to STOKE
paint.setStrokeJoin(Paint.Join.ROUND); // set the join to round you want
paint.setStrokeCap(Paint.Cap.ROUND); // set the paint cap to round too
paint.setPathEffect(new CornerPathEffect(30) ); // set the path effect when they join.
paint.setAntiAlias(true);
// Line current = lines.get(lines.size() - 1);
System.out.println("---penmove---");
float dx = Math.abs((int) event.getX() - mX);
float dy = Math.abs((int) event.getY() - mY);
System.out.println("--Value of dx-dy-"+dx+"-"+dy);
if (dx >= 4 || dy >= 4) {
// setXY function set X and Y values to be used in JS File
mc.setXY((int) event.getX() / scalefactor, (int) event.getY() / scalefactor);
MainActivity.super.loadUrl("javascript:penMove(0,0,'pen')");
path.quadTo(mX,mY,(mX+event.getX())/2,(mY+event.getY())/2);
mX=event.getX();
mY=event.getY();
}
else
{
}
}
} else if (rectanglemode) {
qx = (int) event.getX();
qy = (int) event.getY();
} else if (linemode) {
qx = (int) event.getX();
qy = (int) event.getY();
} else if (circlemode) {
//MainActivity.super.loadUrl("javascript:circleDown(" + eventX + "," + eventY + ")");
}
break;
case MotionEvent.ACTION_UP:
boolean ll = r.contains((int) event.getX(), (int) event.getY());
if (markerMode)
MainActivity.super.loadUrl("javascript:marker12()");
else if (eraseMode) {
MainActivity.super.loadUrl("javascript:penUp()");
isEraserDown="false";
isMarkerDown="false";
System.out.println("--Eraserfromtouch---actionup");
path.lineTo(mX,mY);
mCanvas.drawPath(path,paint);
path= new Path();
// path1= new Path();
paths.add(path);
// MainActivity.super.loadUrl("javascript:eraserfunction1(" + eventX / scalefactor + "," + eventY / scalefactor + "," + mc.getdrawAttributes1() + ")");
}else if (blockerase) {
qx = (int) event.getX();
qy = (int) event.getY();
MainActivity.super.loadUrl("javascript:bigeraserfunction1(" + rx / scalefactor + "," + ry / scalefactor + "," + qx / scalefactor + "," + qy / scalefactor + ")");
}
/*---------------------Pen up for writing on canvas------------------*/
else if (penmode) {
MainActivity.super.loadUrl("javascript:penUp()");
isPenDown="false";
System.out.println("---pen--up---");
path.lineTo(mX,mY);
mCanvas.drawPath(path,paint);
path= new Path();
// path1= new Path();
paths.add(path);
} else if (rectanglemode) {
qx = (int) event.getX();
qy = (int) event.getY();
MainActivity.super.loadUrl("javascript:rectangle(" + rx / scalefactor + "," + ry / scalefactor + "," + qx / scalefactor + "," + qy / scalefactor + ",'" + Prefs.getString(Elucido_APP_CONSTANTS.shared_user_name, "") + "')");
} else if (linemode) {
qx = (int) event.getX();
qy = (int) event.getY();
MainActivity.super.loadUrl("javascript:line(" + rx / scalefactor + "," + ry / scalefactor + "," + qx / scalefactor + "," + qy / scalefactor + ",'" + Prefs.getString(Elucido_APP_CONSTANTS.shared_user_name, "") + "')");
} else if (circlemode) {
c1x = (int) event.getX();
c1y = (int) event.getY();
MainActivity.super.loadUrl("javascript:circleup(" + c1x / scalefactor + "," + c1y / scalefactor + ")");
} else if (textmode) {
cx = (int) event.getX();
cy = (int) event.getY();
opentextDialog((int) (cx / scalefactor), (int) (cy / scalefactor));
}
break;
default:
return false;
}
invalidate();
return true;
}
draw() Method is in thread for continuously receiving points path
public boolean draw() {
//------------------------ Starting Reciving points--------------------------
String s1 = mc.getdrawlinesdual();
words1 = s1.split(",");
float xx11 = Float.parseFloat(words1[0].replaceAll("[\\(\\)\\[\\]\\{\\}]", "")) * scalefactor;
float yy11 = Float.parseFloat(words1[1]) * scalefactor;
float xx21 = Float.parseFloat(words1[2]) * scalefactor;
float yy21 = Float.parseFloat(words1[3].replaceAll("[\\(\\)\\[\\]\\{\\}]", "")) * scalefactor;
System.out.println("---------x" + xx11 + " y" + yy11 + " x2" + xx21 + " y2" + yy21);
if (a1 == 0)
{
System.out.println("----paint from pen--a1 == 0");
Log.d("TAGG", "INTEGER value " + mc.getdrawAttributes());
if (mc.getdrawTypeAttributes().toString().compareTo("eraser") == 0) {
System.out.println("Eraser--a1==0---ifllop");
Log.d("Eraser", "Im eraser");
String thh = mc.getdrawThAttributes();
float f = Float.parseFloat(thh);
paint1.setStrokeWidth(f);
if (bckimage == null) {
paint1.setColor(Color.WHITE); //Toast.makeText(getContext(),"ERASE",Toast.LENGTH_LONG).show();
} else {
paint1.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
}
} else {
System.out.println("Eraser--a1==0---elsellop");
String th = mc.getdrawThAttributes();
float f = Float.parseFloat(th);
paint1.setColor(color);
}
String t = mc.getdrawTypeAttributes().trim();
if ((t.compareTo("marker") == 0)) {
Log.d("MARKER", "Hi im marker");
String col = mc.getdrawColorAttributes().substring(1);
col = col.toLowerCase();
col = "#ff" + col.trim();
int coll = Color.parseColor(col);
paint1.setColor(coll);
paint1.setAlpha(10);
paint1.setStrokeWidth(20);
if (bckimage == null) {
} else {
paint1.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.XOR));
}
}
path1.moveTo(xx11, yy11);
// path1.lineTo(xx21, yy21);
path1.quadTo(xx11, yy11, (xx11 + xx21) / 2, (yy11 + yy21) / 2);
// invalidate();
// type.add("Line");
path1 = new Path();
a1 = xx11;
b1 = yy11;
c1 = xx21;
d1 = yy21;
}
else if (a1 == xx11)
{
//il.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
System.out.println("----paint from pen--a1 == xx11");
MainActivity.this.blankwhiteboard = 1;
path1.moveTo(c1, d1);
// float x = c+(xx2-c)/2;
// float y= d+(yy2-d)/2;
path1.quadTo(c1, d1, (c1 + xx21) / 2, (d1 + yy21) / 2);
// path1.lineTo(xx21, yy21);
invalidate();
c1 = xx21;
d1 = yy21;
}
else
{
type.add("Line");
System.out.println("----paint from pen");
path1 = new Path();
paint1 = new Paint();
paint1.setAntiAlias(true);
String th = mc.getdrawThAttributes();
paint1.setStyle(Paint.Style.STROKE);
paint1.setStrokeJoin(Paint.Join.ROUND);
paint1.setStrokeCap(Paint.Cap.ROUND);
paint1.setPathEffect(new CornerPathEffect(30));
paint1.setDither(true);
String t = mc.getdrawTypeAttributes();
if (mc.getdrawTypeAttributes().toString().compareTo("eraser") == 0)
{
System.out.println("Eraser--a1!=0---ifllop");
System.out.println("inside cuming erase");
//float val = 20;
String thh = mc.getdrawThAttributes();
float f = Float.parseFloat(thh);
paint1.setStrokeWidth(f);
Log.d("Eraser", "Im in eraser");
if (bckimage == null) {
paint1.setColor(Color.WHITE); //Toast.makeText(getContext(),"ERASE",Toast.LENGTH_LONG).show();
} else
paint1.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
invalidate();
}
else
{
System.out.println("Eraser--a1!=0---elsellop");
float f = Float.parseFloat(th);
paint1.setStrokeWidth(f);
String col = mc.getdrawColorAttributes().substring(1);
col = col.toLowerCase();
col = "#ff" + col;
int coll = Color.parseColor(col);
paint1.setColor(coll);
if ((t.compareTo("marker") == 0))
{
Log.d("MARKER", "Hi im marker");
paint1.setAlpha(10);
paint1.setStrokeWidth(20);
if (bckimage == null)
{
}
else
{
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.XOR));
}
paint1.setStrokeWidth(f);
mc.getTelephoneNumber(Integer.toHexString(color).substring(2));
MainActivity.super.loadUrl("javascript:colorSelectListener('')");
}
else
{
}
}
path1.moveTo(xx11, yy11);
// path1.lineTo(xx21,yy21);
path1.quadTo(xx11, yy11, (xx11 + xx21) / 2, (yy11 + yy21) / 2);
a1 = xx11;
b1 = yy11;
c1 = xx21;
d1 = yy21;
}
invalidate();
//------------------------ End Reciving points--------------------------
}
first this is my textureView class
public abstract class ScalableTextureView extends TextureView{
private static final boolean SHOW_LOGS = false;
private static final String TAG = ScalableTextureView.class.getSimpleName();
private Integer mContentWidth;
private Integer mContentHeight;
private float mPivotPointX = 0f;
private float mPivotPointY = 0f;
private float mContentScaleX = 1f;
private float mContentScaleY = 1f;
private float mContentRotation = 0f;
private float mContentScaleMultiplier = 1f;
private int mContentX = 0;
private int mContentY = 0;
private final Matrix mTransformMatrix = new Matrix();
private ScaleType mScaleType;
public enum ScaleType {
CENTER_CROP, TOP, BOTTOM, FILL,FITX
}
public ScalableTextureView(Context context) {
super(context);
}
public ScalableTextureView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ScalableTextureView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public ScalableTextureView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
public void setScaleType(ScaleType scaleType) {
mScaleType = scaleType;
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (SHOW_LOGS) Logger.v(TAG, "onMeasure, mContentoWidth " + mContentWidth + ", mContentHeight " + mContentHeight);
if (mContentWidth != null && mContentHeight != null) {
updateTextureViewSize();
}
}
public void updateTextureViewSize() {
if (SHOW_LOGS) Logger.d(TAG, ">> updateTextureViewSize");
if (mContentWidth == null || mContentHeight == null) {
throw new RuntimeException("null content size");
}
float viewWidth = getMeasuredWidth();
float viewHeight = getMeasuredHeight();
float contentWidth = mContentWidth;
float contentHeight = mContentHeight;
if (SHOW_LOGS) {
Logger.v(TAG, "updateTextureViewSize, mContentWidth " + mContentWidth + ", mContentHeight " + mContentHeight + ", mScaleType " + mScaleType);
Logger.v(TAG, "updateTextureViewSize, viewWidth " + viewWidth + ", viewHeight " + viewHeight);
}
float scaleX = 1.0f;
float scaleY = 1.0f;
switch (mScaleType) {
case FILL:
if (viewWidth > viewHeight) { // device in landscape
scaleX = (viewHeight * contentWidth) / (viewWidth * contentHeight);
} else {
scaleY = (viewWidth * contentHeight) / (viewHeight * contentWidth);
}
break;
case BOTTOM:
case CENTER_CROP:
case FITX:
case TOP:
if (contentWidth > viewWidth && contentHeight > viewHeight) {
scaleX = contentWidth / viewWidth;
scaleY = contentHeight / viewHeight;
} else if (contentWidth < viewWidth && contentHeight < viewHeight) {
scaleY = viewWidth / contentWidth;
scaleX = viewHeight / contentHeight;
} else if (viewWidth > contentWidth) {
scaleY = (viewWidth / contentWidth) / (viewHeight / contentHeight);
} else if (viewHeight > contentHeight) {
scaleX = (viewHeight / contentHeight) / (viewWidth / contentWidth);
}
break;
}
if (SHOW_LOGS) {
Logger.v(TAG, "updateTextureViewSize, scaleX " + scaleX + ", scaleY " + scaleY);
}
// Calculate pivot points, in our case crop from center
float pivotPointX;
float pivotPointY;
switch (mScaleType) {
case TOP:
pivotPointX = 0;
pivotPointY = 0;
break;
case BOTTOM:
pivotPointX = viewWidth;
pivotPointY = viewHeight;
break;
case CENTER_CROP:
pivotPointX = viewWidth / 2;
pivotPointY = viewHeight / 2;
break;
case FITX:
pivotPointX = viewWidth ;
pivotPointY = viewHeight ;
break;
case FILL:
pivotPointX = mPivotPointX;
pivotPointY = mPivotPointY;
break;
default:
throw new IllegalStateException("pivotPointX, pivotPointY for ScaleType " + mScaleType + " are not defined");
}
if (SHOW_LOGS)
Logger.v(TAG, "updateTextureViewSize, pivotPointX " + pivotPointX + ", pivotPointY " + pivotPointY);
float fitCoef = 1;
switch (mScaleType) {
case FILL:
break;
case BOTTOM:
case CENTER_CROP:
case TOP:
if (mContentHeight > mContentWidth) { //Portrait video
fitCoef = viewWidth / (viewWidth * scaleX);
} else { //Landscape video
fitCoef = viewHeight / (viewHeight * scaleY);
}
break;
}
mContentScaleX = fitCoef * scaleX;
mContentScaleY = fitCoef * scaleY;
mPivotPointX = pivotPointX;
mPivotPointY = pivotPointY;
updateMatrixScaleRotate();
if (SHOW_LOGS) Logger.d(TAG, "<< updateTextureViewSize");
}
private void updateMatrixScaleRotate() {
if (SHOW_LOGS) Logger.d(TAG, ">> updateMatrixScaleRotate, mContentRotation " + mContentRotation + ", mContentScaleMultiplier " + mContentScaleMultiplier + ", mPivotPointX " + mPivotPointX + ", mPivotPointY " + mPivotPointY);
mTransformMatrix.reset();
mTransformMatrix.setScale(mContentScaleX * mContentScaleMultiplier, mContentScaleY * mContentScaleMultiplier, mPivotPointX, mPivotPointY);
mTransformMatrix.postRotate(mContentRotation, mPivotPointX, mPivotPointY);
setTransform(mTransformMatrix);
if (SHOW_LOGS) Logger.d(TAG, "<< updateMatrixScaleRotate, mContentRotation " + mContentRotation + ", mContentScaleMultiplier " + mContentScaleMultiplier + ", mPivotPointX " + mPivotPointX + ", mPivotPointY " + mPivotPointY);
}
private void updateMatrixTranslate() {
if (SHOW_LOGS) {
Logger.d(TAG, "updateMatrixTranslate, mContentX " + mContentX + ", mContentY " + mContentY);
}
float scaleX = mContentScaleX * mContentScaleMultiplier;
float scaleY = mContentScaleY * mContentScaleMultiplier;
mTransformMatrix.reset();
mTransformMatrix.setScale(scaleX, scaleY, mPivotPointX, mPivotPointY);
mTransformMatrix.postTranslate(mContentX, mContentY);
setTransform(mTransformMatrix);
}
#Override
public void setRotation(float degrees) {
if (SHOW_LOGS)
Logger.d(TAG, "setRotation, degrees " + degrees + ", mPivotPointX " + mPivotPointX + ", mPivotPointY " + mPivotPointY);
mContentRotation = degrees;
updateMatrixScaleRotate();
}
#Override
public float getRotation() {
return mContentRotation;
}
#Override
public void setPivotX(float pivotX) {
if (SHOW_LOGS) Logger.d(TAG, "setPivotX, pivotX " + pivotX);
mPivotPointX = pivotX;
}
#Override
public void setPivotY(float pivotY) {
if (SHOW_LOGS) Logger.d(TAG, "setPivotY, pivotY " + pivotY);
mPivotPointY = pivotY;
}
#Override
public float getPivotX() {
return mPivotPointX;
}
#Override
public float getPivotY() {
return mPivotPointY;
}
public float getContentAspectRatio() {
return mContentWidth != null && mContentHeight != null
? (float) mContentWidth / (float) mContentHeight
: 0;
}
/**
* Use it to animate TextureView content x position
* #param x
*/
public final void setContentX(float x) {
mContentX = (int) x - (getMeasuredWidth() - getScaledContentWidth()) / 2;
updateMatrixTranslate();
}
/**
* Use it to animate TextureView content x position
* #param y
*/
public final void setContentY(float y) {
mContentY = (int) y - (getMeasuredHeight() - getScaledContentHeight()) / 2;
updateMatrixTranslate();
}
protected final float getContentX() {
return mContentX;
}
protected final float getContentY() {
return mContentY;
}
/**
* Use it to set content of a TextureView in the center of TextureView
*/
public void centralizeContent() {
int measuredWidth = getMeasuredWidth();
int measuredHeight = getMeasuredHeight();
int scaledContentWidth = getScaledContentWidth();
int scaledContentHeight = getScaledContentHeight();
if (SHOW_LOGS) Logger.d(TAG, "centralizeContent, measuredWidth " + measuredWidth + ", measuredHeight " + measuredHeight + ", scaledContentWidth " + scaledContentWidth + ", scaledContentHeight " + scaledContentHeight);
mContentX = 0;
mContentY = 0;
if (SHOW_LOGS) Logger.d(TAG, "centerVideo, mContentX " + mContentX + ", mContentY " + mContentY);
updateMatrixScaleRotate();
}
public Integer getScaledContentWidth() {
return (int) (mContentScaleX * mContentScaleMultiplier * getMeasuredWidth());
}
public Integer getScaledContentHeight() {
return (int) (mContentScaleY * mContentScaleMultiplier * getMeasuredHeight());
}
public float getContentScale() {
return mContentScaleMultiplier;
}
public void setContentScale(float contentScale) {
if (SHOW_LOGS) Logger.d(TAG, "setContentScale, contentScale " + contentScale);
mContentScaleMultiplier = contentScale;
updateMatrixScaleRotate();
}
protected final void setContentHeight(int height) {
mContentHeight = height;
}
protected final Integer getContentHeight() {
return mContentHeight;
}
protected final void setContentWidth(int width) {
mContentWidth = width;
}
protected final Integer getContentWidth() {
return mContentWidth;
}
}
now all the scale type fill , top , bottom ... not shown all video size its crop part from Video when i play it i just try to add scale type FITX for show all video no cropping
i try this for crop in Fit X
case FITX:
double aspectRatio = (double) viewHeight / viewWidth;
float newWidth, newHeight;
if (viewHeight > (int) (viewWidth* aspectRatio)) {
newWidth = viewWidth;
newHeight = (int) (viewWidth* aspectRatio);
} else {
// limited by short height; restrict width
newWidth = (int) (viewHeight/ aspectRatio);
newHeight = viewHeight;
}
pivotPointX = newWidth ;
pivotPointY = newHeight ;
break;
but its like scale BOTTOM or TOP i don't know how to solve it complicated to me
NOTE ** FITX added by me in code
I'm using custom TextureView which has zooming feature(for android player). The problem is I can not do accurate zooming. when you try zooming in first time it seems work without problem. After some zooming view jumps to another position. I will put custom textureView code here:
public class PanZoomTextureView extends TextureView {
protected Context mContext;
protected float mPosX;
protected float mPosY;
protected float mFocusX; // these two focus variables are not needed
protected float mFocusY;
protected float mLastTouchX;
protected float mLastTouchY;
protected static final int INVALID_POINTER_ID = -1;
// The ‘active pointer’ is the one currently moving our object.
protected int mActivePointerId = INVALID_POINTER_ID;
protected ScaleGestureDetector mScaleDetector;
protected float mScaleFactor = 1.f;
// The next three are set by calling supportsPan, supportsZoom, ...
protected boolean mSupportsPan = true;
protected boolean mSupportsZoom = true;
private MediaController controller;
/**
*/
public PanZoomTextureView(Context context) {
this(context, null, 0);
}
public PanZoomTextureView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public PanZoomTextureView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mContext = context;
setupScaleDetector(context);
}
private void invalidateDraw() {
Matrix ma = new Matrix();
float x = 0, y = 0;
x = mPosX;
y = mPosY;
if (mSupportsZoom || mSupportsPan) {
if (mSupportsPan && mSupportsZoom) {
if (mScaleDetector.isInProgress()) {
ma.setScale(mScaleFactor, mScaleFactor, mFocusX, mFocusY);
mPosX = (getWidth() - getWidth() * mScaleFactor) * (mFocusX / getWidth()) / 2;
mPosY = (getHeight() - getHeight() * mScaleFactor) * (mFocusY / getHeight()) / 2;
Log.d("Multitouch", "'in progress' mposx, mposy, focusX, focusY: " + mPosX + " " + mPosY + " " + mFocusX + " " + mFocusY);
} else {
// Pinch zoom is not in progress. Just do translation
// of canvas at whatever the current scale is.
ma.setTranslate(x, y);
ma.postScale(mScaleFactor, mScaleFactor);
Log.d("Multitouch", "x, y , focusX, focusY , scalefactor : " + x + " " + y + " " + mFocusX + " " + mFocusY + " " + mScaleFactor);
}
}
}
setTransform(ma);
}
public void setMediaController(MediaController c) {
this.controller = c;
}
/**
* Handle touch and multitouch events so panning and zooming can be supported.
*/
#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);
Log.d("OnTouchDown:", "lastX, lastY: " + mLastTouchX + " , " + mLastTouchY);
if (ev.getPointerCount() == 1) {
if (controller.isShowing()) {
controller.hide();
} else {
controller.show(10000);
}
}
break;
}
case MotionEvent.ACTION_MOVE: {
//register active pointer index
final int pointerIndex = ev.findPointerIndex(mActivePointerId);
// x and y values from active pointer
final float x = ev.getX(pointerIndex);
final float y = ev.getY(pointerIndex);
final float dx = (x - mLastTouchX);
final float dy = (y - mLastTouchY);
// Only move if the view supports panning and
// ScaleGestureDetector isn't processing a gesture.
if (!mScaleDetector.isInProgress()) {
Log.d("OnTouch1:", "dX, dY: " + dx + " , " + dy);
if (mPosX > 5) {
mPosX = 3;
}
if (mPosY > 5) {
mPosY = 3;
}
if (mPosX < ((-1) * (getWidth() - getWidth() / mScaleFactor) - 5)) {
mPosX = ((-1) * (getWidth() - getWidth() / mScaleFactor) - 2);
}
if (mPosY < ((-1) * (getHeight() - getHeight() / mScaleFactor) - 5)) {
mPosY = ((-1) * (getHeight() - getHeight() / mScaleFactor) - 2);
}
if ((mPosX + dx) > 5 && (mPosY + dy) > 5) {
mPosX = 3;
mPosY = 3;
Log.d("OnTouch1:", "mPosx, mPosy: " + mPosX + " , " + mPosY);
} else if ((mPosY + dy) > 5 && (mPosX + dx) < 5 && (mPosX + dx) > ((-1) * (getWidth() - getWidth() / mScaleFactor) - 5)) {
mPosY = 3;
mPosX += dx;
Log.d("OnTouch2:", "mPosx, mPosy: " + mPosX + " , " + mPosY);
} else {
mPosX += dx;
mPosY += dy;
Log.d("OnTouch8:", "mPosx, mPosy: " + mPosX + " , " + mPosY);
}
invalidateDraw();
}
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;
}
}
return true;
}
/**
* This method sets up the scale detector object used by the view. It is called by the constructor.
*
* #return void
*/
protected void setupScaleDetector(Context context) {
// Create our ScaleGestureDetector
mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
}
/**
* ScaleListener
*/
protected class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
#Override
public boolean onScale(ScaleGestureDetector detector) {
mScaleFactor *= detector.getScaleFactor();
Log.e("Multitouch", "-------scaling factor:" + mScaleFactor);
// Don't let the object get too small or too large.
mScaleFactor = Math.max(1.f, Math.min(mScaleFactor, 4));
mFocusX = detector.getFocusX();
mFocusY = detector.getFocusY();
invalidateDraw();
return true;
}
}
}
Also if someone wants to test real project here is the link: https://github.com/Shuhrat-java/PanZoomPlayer
I want to calculate the un-scaled absolute position of the image drawn on the canvas based on the position clicked by the user on the scaled canvas.
I used following zoom implementation
Translate/scale bitmap within boundaries?
So far,
public boolean inMe(int x, int y, Region ClickRegion) {
if(mScaleFactor == 0)
mScaleFactor = 1;
float curX = ((x*1.0f)/ mScaleFactor) - (mPosX * mScaleFactor);
float curY = ((y*1.0f) / mScaleFactor) - (mPosY * mScaleFactor);
x = (int)curX;
y = (int)curY;
//ClickRegion is a grapics.Region computed on non-zoomed coordinates
if (ClickRegion.contains(x, y))
return true;
else
return false;
}
This works fine, when there is no zooming, but when its zoomed there are significant issues.
EDIT
This is the algo I used for zooming and panning.
public class PanZoomView extends View {
public static final String TAG = PanZoomView.class.getName();
private static final int INVALID_POINTER_ID = -1;
// The ‘active pointer’ is the one currently moving our object.
private int mActivePointerId = INVALID_POINTER_ID;
private Bitmap bitmap;
private float viewHeight;
private float viewWidth;
float canvasWidth, canvasHeight;
private ScaleGestureDetector mScaleDetector;
private float mScaleFactor = 1.f;
private float minScaleFactor;
private float mPosX;
private float mPosY;
private float mLastTouchX, mLastTouchY;
private boolean firstDraw = true;
private boolean panEnabled = true;
private boolean zoomEnabled = true;
public PanZoomView(Context context) {
super(context);
setup();
}
public PanZoomView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setup();
}
public PanZoomView(Context context, AttributeSet attrs) {
super(context, attrs);
setup();
}
private void setup() {
mScaleDetector = new ScaleGestureDetector(getContext(), new ScaleListener());
}
public void setBitmap(Bitmap bmp) {
setImageBitmap(bmp);
}
public void setImageBitmap(Bitmap bmp) {
bitmap = bmp;
resetZoom();
resetPan();
firstDraw = true;
invalidate();
}
public Bitmap getImageBitmap() {
return bitmap;
}
public Bitmap getBitmap() {
return getImageBitmap();
}
public void resetZoom() {
mScaleFactor = 1.0f;
}
public void resetPan() {
mPosX = 0f;
mPosY = 0f;
}
public void setImageDrawable(Drawable drawable) {
setImageBitmap(((BitmapDrawable) drawable).getBitmap());
}
public BitmapDrawable getImageDrawable() {
BitmapDrawable bd = new BitmapDrawable(getContext().getResources(), bitmap);
return bd;
}
public BitmapDrawable getDrawable() {
return getImageDrawable();
}
public void onDraw(Canvas canvas) {
// Log.v(TAG, "onDraw()");
if (bitmap == null) {
Log.w(TAG, "nothing to draw - bitmap is null");
super.onDraw(canvas);
return;
}
if (firstDraw
&& (bitmap.getHeight() > 0)
&& (bitmap.getWidth() > 0)) {
//Don't let the user zoom out so much that the image is smaller
//than its containing frame
float minXScaleFactor = (float) viewWidth / (float) bitmap.getWidth();
float minYScaleFactor = (float) viewHeight / (float) bitmap.getHeight();
minScaleFactor = Math.max(minXScaleFactor, minYScaleFactor);
Log.d(TAG, "minScaleFactor: " + minScaleFactor);
mScaleFactor = minScaleFactor; //start out "zoomed out" all the way
mPosX = mPosY = 0;
firstDraw = false;
}
mScaleFactor = Math.max(mScaleFactor, minScaleFactor);
canvasHeight = canvas.getHeight();
canvasWidth = canvas.getWidth();
// Log.d(TAG, "canvas density: " + canvas.getDensity() + " bitmap density: " + bitmap.getDensity());
// Log.d(TAG, "mScaleFactor: " + mScaleFactor);
//Save the canvas without translating (panning) or scaling (zooming)
//After each change, restore to this state, instead of compounding
//changes upon changes
canvas.save();
int maxX, minX, maxY, minY;
//Regardless of the screen density (HDPI, MDPI) or the scale factor,
//The image always consists of bitmap width divided by 2 pixels. If an image
//is 200 pixels wide and you scroll right 100 pixels, you just scrolled the image
//off the screen to the left.
minX = (int) (((viewWidth / mScaleFactor) - bitmap.getWidth()) / 2);
maxX = 0;
//How far can we move the image vertically without having a gap between image and frame?
minY = (int) (((viewHeight / mScaleFactor) - bitmap.getHeight()) / 2);
maxY = 0;
Log.d(TAG, "minX: " + minX + " maxX: " + maxX + " minY: " + minY + " maxY: " + maxY);
//Do not go beyond the boundaries of the image
if (mPosX > maxX) {
mPosX = maxX;
}
if (mPosX < minX) {
mPosX = minX;
}
if (mPosY > maxY) {
mPosY = maxY;
}
if (mPosY < minY) {
mPosY = minY;
}
// Log.d(TAG, "view width: " + viewWidth + " view height: "
// + viewHeight);
// Log.d(TAG, "bitmap width: " + bitmap.getWidth() + " height: " + bitmap.getHeight());
// Log.d(TAG, "translating mPosX: " + mPosX + " mPosY: " + mPosY);
// Log.d(TAG, "zooming to scale factor of " + mScaleFactor);
canvas.scale(mScaleFactor, mScaleFactor);
// Log.d(TAG, "panning to " + mPosX + "," + mPosY);
canvas.translate(mPosX, mPosY);
super.onDraw(canvas);
canvas.drawBitmap(bitmap, mPosX, mPosY, null);
canvas.restore(); //clear translation/scaling
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
// Let the ScaleGestureDetector inspect all events.
if (zoomEnabled) {
mScaleDetector.onTouchEvent(ev);
}
if (panEnabled) {
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()) {
float dx = x - mLastTouchX;
float dy = y - mLastTouchY;
//Adjust for zoom factor. Otherwise, the user's finger moving 10 pixels
//at 200% zoom causes the image to slide 20 pixels instead of perfectly
//following the user's touch
dx /= (mScaleFactor * 2);
dy /= (mScaleFactor * 2);
mPosX += dx;
mPosY += dy;
Log.v(TAG, "moving by " + dx + "," + dy + " mScaleFactor: " + mScaleFactor);
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;
}
}
}
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));
// Log.d(TAG, "detector scale factor: " + detector.getScaleFactor() + " mscalefactor: " + mScaleFactor);
invalidate();
return true;
}
}
//Currently zoomEnabled/panEnabled can only be set programmatically, not in XML
public boolean isPanEnabled() {
return panEnabled;
}
public void setPanEnabled(boolean panEnabled) {
this.panEnabled = panEnabled;
}
public boolean isZoomEnabled() {
return zoomEnabled;
}
public void setZoomEnabled(boolean zoomEnabled) {
this.zoomEnabled = zoomEnabled;
}
/**
* Calls getCroppedBitmap(int outputWidth, int outputHeight) without
* scaling the resulting bitmap to any specific size.
* #return
*/
public Bitmap getCroppedBitmap() {
return getCroppedBitmap(0, 0);
}
/**
* Takes the section of the bitmap visible in its View object
* and exports that to a Bitmap object, taking into account both
* the translation (panning) and zoom (scaling).
* WARNING: run this in a separate thread, not on the UI thread!
* If you specify that a 200x200 image should have an outputWidth
* of 400 and an outputHeight of 50, the image will be squished
* and stretched to those dimensions.
* #param outputWidth desired width of output Bitmap in pixels
* #param outputHeight desired height of output Bitmap in pixels
* #return the visible portion of the image in the PanZoomImageView
*/
public Bitmap getCroppedBitmap(int outputWidth, int outputHeight) {
int origX = -1 * (int) mPosX * 2;
int origY = -1 * (int) mPosY * 2;
int width = (int) (viewWidth / mScaleFactor);
int height = (int) (viewHeight / mScaleFactor);
Log.e(TAG, "origX: " + origX + " origY: " + origY + " width: " + width + " height: " + height + " outputWidth: " + outputWidth + " outputHeight: " + outputHeight + "getLayoutParams().width: " + getLayoutParams().width + " getLayoutParams().height: " + getLayoutParams().height);
Bitmap b = Bitmap.createBitmap(bitmap, origX, origY, width, height);
if (outputWidth > 0 && outputWidth > 0) {
//Use the exact dimensions given--chance this won't match the aspect ratio
b = Bitmap.createScaledBitmap(b, outputWidth, outputHeight, true);
}
return b;
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
viewHeight = h;
viewWidth = w;
}
}
Thanks for all comment, but this worked for me.
public boolean inMe(int x, int y, Region ClickRegion) {
float curX = ((x*1.0f)) + (-1*mPosX * 2* mScaleFactor);
float curY = ((y*1.0f)) + (-1*mPosY * 2* mScaleFactor);
x = (int)((curX/ mScaleFactor));
y = (int)((curY/ mScaleFactor));
if (cluster.ClickRegion.contains(x, y))
return true;
else
return false;
}
i want to custom view,it can include some effect:first draw a pic on the view as a background then draw a rectangle on the image,and draw other image named A in the rectangle, we know the rectangle have four fixed point,when i drag one of these,the rectangle can scale,at the same time A also is scale, i have read more link,but not find good example,i have done something,but cannot finish the scale rectangle,my code is:
public class DrawView extends View implements OnTouchListener {
private static final String TAG = "DrawView";
private static final int LineLength = 30;
Paint paint = new Paint();
float locationX, locationY;
private int mLastTouchX;
private int mLastTouchY;
private int mPosX;
private int mPosY;
private int mPosX1;
private int mPosY1;
Bitmap bitmap, bmp, xiao;
int screenWidth, screenHeight;
int xLength;
boolean isFirst = true;
boolean isLeft = false;
Rect r, rBig,outRect;
public DrawView(Context context) {
super(context);
setFocusable(true);
setFocusableInTouchMode(true);
this.setOnTouchListener(this);
WindowManager wm = (WindowManager) context
.getSystemService(Context.WINDOW_SERVICE);
screenHeight = wm.getDefaultDisplay().getHeight();
screenWidth = wm.getDefaultDisplay().getWidth();
mPosX = screenWidth / 2;
mPosY = screenHeight / 2;
paint.setColor(Color.RED);
paint.setAntiAlias(true);
bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.meinv);
bmp = BitmapFactory.decodeResource(getResources(), R.drawable.icon);
xiao = BitmapFactory.decodeResource(getResources(),
R.drawable.msn_protocol);
xLength = (int) Math.hypot(xiao.getWidth(), xiao.getHeight());
r = new Rect();
r.set((int) mPosX - LineLength - xiao.getWidth(), (int) mPosY
- LineLength - xiao.getHeight(), (int) mPosX - LineLength,
(int) mPosY - LineLength);
// Log.i("r", r.left + " " + r.top + " " + r.right + " " + r.bottom);
rBig = new Rect();
rBig.set((int) mPosX - LineLength, (int) mPosY - LineLength,
(int) mPosX + LineLength, (int) mPosY + LineLength);
//Log.i("r", rBig.left + " " + rBig.top + " " + rBig.right + " " + rBig.bottom);
}
#Override
public void onDraw(Canvas canvas) {
canvas.drawBitmap(bitmap, 0, 0, null);
canvas.drawBitmap(xiao, mPosX - LineLength - xiao.getWidth(), mPosY
- LineLength - xiao.getHeight(), null);
canvas.drawLine(mPosX - LineLength,
mPosY - LineLength - xiao.getHeight() / 2, mPosX + LineLength,
mPosY - LineLength - xiao.getHeight() / 2, paint);
canvas.drawLine(mPosX - LineLength - xiao.getWidth() / 2, mPosY
- LineLength, mPosX - LineLength - xiao.getWidth() / 2, mPosY
+ LineLength, paint);
canvas.drawBitmap(xiao, mPosX + LineLength,
mPosY - LineLength - xiao.getHeight(), null);
canvas.drawBitmap(xiao, mPosX - LineLength - xiao.getWidth(), mPosY
+ LineLength, null);
canvas.drawBitmap(xiao, mPosX + LineLength, mPosY + LineLength, null);
canvas.drawLine(mPosX + LineLength + xiao.getWidth() / 2, mPosY
- LineLength, mPosX + LineLength + xiao.getWidth() / 2, mPosY
+ LineLength, paint);
canvas.drawLine(mPosX - LineLength,
mPosY + LineLength + xiao.getHeight() / 2, mPosX + LineLength,
mPosY + LineLength + xiao.getHeight() / 2, paint);
if (isLeft) {
Matrix matrix = new Matrix();
matrix.preScale(0.8f, 0.8f);
Bitmap rotatedBitmap = Bitmap.createBitmap(bmp, 0, 0,
bmp.getWidth(), bmp.getHeight(), matrix, true);
canvas.drawBitmap(rotatedBitmap, mPosX - LineLength, mPosY
- LineLength, null);
}
}
public boolean onTouch(View view, MotionEvent event) {
isFirst = false;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
mPosX1 = (int) event.getX();
mPosY1 = (int) event.getY();
mLastTouchX = mPosX1;
mLastTouchY = mPosX1;
// Log.i("r", r.left + " " + r.top + " " + r.right + " " + r.bottom);
Log.i("ACTION_DOWN", "" + mPosX1 + " " + mPosY1);
if (r.contains(mPosX1, mPosY1)) {
isLeft = true;
invalidate();
}
break;
}
case MotionEvent.ACTION_MOVE: {
int x = (int) event.getX();
int y = (int) event.getY();
Log.i("aa",""+x+""+y);
int dx = x - mLastTouchX;
int dy = y - mLastTouchY;
mLastTouchX = x;
mLastTouchY = y;
mPosX += dx;
mPosY += dy;
r.set((int) mPosX - LineLength - xiao.getWidth(), (int) mPosY
- LineLength - xiao.getHeight(), (int) mPosX - LineLength,
(int) mPosY - LineLength);
rBig.set((int) mPosX - LineLength, (int) mPosY - LineLength,
(int) mPosX + LineLength, (int) mPosY + LineLength);
// Log.i("r", rBig.left + " " + rBig.top + " " + rBig.right + " " + rBig.bottom);
invalidate();
break;
}
case MotionEvent.ACTION_UP: {
break;
}
case MotionEvent.ACTION_CANCEL: {
break;
}
}
return true;
}
}
the pic as :http://i.stack.imgur.com/wxi35.png,the effect have finished by system gallery,but i debug the source ,i failed, as my other question: Imitate crop function of system Gallery
and https://stackoverflow.com/questions/6724218/i-cannot-find-the-initial-value-in-gallery-the-source
I dont know about drawing the Rectangle but, this is how I moved the image
MainPinchView.java
public class MainPinchView extends Activity {
int menuid = 0;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MainPinchImageView obj = new MainPinchImageView(this);
Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.my);
obj.setImage(bmp, 100, 100);
setContentView(obj);
}
}
MainPinchImageView.java
public class MainPinchImageView extends ImageView {
private static final String TAG = "Touch";
// These matrices will be used to move and zoom image
Matrix matrix = new Matrix();
Matrix savedMatrix = new Matrix();
int flag = 0;
// 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;
Context context;
public MainPinchImageView(Context context) {
super(context);
super.setClickable(true);
this.context = context;
matrix.setTranslate(1f, 1f);
setImageMatrix(matrix); // sets the default matrix
setScaleType(ScaleType.MATRIX); //Controls how the image should be resized or moved to match the size of this ImageView.
setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent 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_MOVE:
if (mode == DRAG) {
// ...
matrix.set(savedMatrix);
matrix.postTranslate(event.getX() - start.x, event.getY()- start.y);
}
break;
}
setImageMatrix(matrix);
return true; // indicate event was handled
}
});
}
public void setImage(Bitmap bm, int displayWidth, int displayHeight) {
super.setImageBitmap(bm);
int displayheight = (getResources().getDisplayMetrics().heightPixels)/2;
int displaywidth = (getResources().getDisplayMetrics().widthPixels)/2;
int imgw = displayWidth/2;
int imgh = displayHeight/2;
// Fit to screen.
float scale;
if ((displayHeight / bm.getHeight()) >= (displayWidth / bm.getWidth())) {
scale = (float) displayWidth / (float) bm.getWidth();
} else {
scale = (float) displayHeight / (float) bm.getHeight();
}
savedMatrix.set(matrix);
matrix.set(savedMatrix);
matrix.postScale(scale, scale, mid.x, mid.y);
setImageMatrix(matrix);
savedMatrix.set(matrix);
matrix.set(savedMatrix);
matrix.postTranslate(displaywidth - imgw, displayheight - imgh);
setImageMatrix(matrix);
}
}