Rotar y cambiar el tamaño de la vista de imagen con un solo dedo en android

Estoy desarrollando una aplicación que tiene la característica de cambiar el tamaño y la rotación de la vista de la imagen arrastrando su botón de esquina inferior derecha.

He visto una aplicación que tiene la característica de que si arrastrar el botón de esquina inferior derecha diagonalmente tamaño de la imagen había cambiado de tamaño o si arrastra el botón a la izquierda o derecha dirección imageview había girado como por la dirección. Deseo implementar esta función en mi aplicación.

Estoy luchando para implementar la rotación de un solo dedo, así como el cambio de tamaño de la imagen.

Por favor, guíame de manera correcta. Introduzca aquí la descripción de la imagen


Estoy intentando este código, e intento aplicar el zumbido y girar pero no capaz de hacer por favor me ayuda. Belove código para hacer zoom y girar la acción de la base de los dedos.

public class ScaleActivity extends Activity { ViewGroup lLayout; static ImageView img, backgrndImg; Canvas mCanvas; float d; private float mAspectQuotient; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); lLayout = (FrameLayout) findViewById(R.id.lLayout); final CropView cv = new CropView(this); lLayout.addView(cv); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } public class CropView extends ImageView { private static final int SELECTION_RECT_PAINT_COLOR = 0xFF000000; private static final int SELECTION_RECT_FILL_COLOR = 0x70FFFFFF; private static final int TOUCH_TOLERANCE = 25; private static final int xInc = 25; private static final int yInc = 25; Paint paint = new Paint(); private int initial_size = 200; private Point leftTop, rightBottom, center, previous, currentPoint, rectPos; private Paint fillPaint; private Paint rectPaint; protected Rect selection, dest; private boolean isAffectedBottom = false; Bitmap bitmap, backgroundBitmap; Rect rectf; Rect knobRect; private Context mContext; int width, height; private Matrix matrix = new Matrix(); Bitmap resizedBitmap; // Adding parent class constructors public CropView(Context context) { super(context); mContext = context; backgroundBitmap = BitmapFactory.decodeResource(getContext() .getResources(), R.drawable.toast_bkgrd); bitmap = BitmapFactory.decodeResource(getContext().getResources(), R.drawable.aviary_adjust_knob); rectPaint = new Paint(); rectPaint.setStyle(Style.STROKE); rectPaint.setColor(SELECTION_RECT_PAINT_COLOR); fillPaint = new Paint(); fillPaint.setStyle(Style.FILL); fillPaint.setColor(SELECTION_RECT_FILL_COLOR); currentPoint = new Point(getWidth() / 2, getHeight() / 2); width = backgroundBitmap.getWidth(); height = backgroundBitmap.getHeight(); initCropView(); } public CropView(Context context, AttributeSet attrs) { super(context, attrs, 0); initCropView(); } public CropView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); initCropView(); } @SuppressLint("DrawAllocation") @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mCanvas = canvas; if (leftTop.equals(0, 0)) resetPoints(); mCanvas.save(); resizedBitmap = Bitmap.createBitmap(backgroundBitmap, 0, 0, backgroundBitmap.getWidth(), backgroundBitmap.getHeight(), matrix, true); // mCanvas.drawBitmap(backgroundBitmap, matrix, rectPaint); mCanvas.drawBitmap(resizedBitmap, null, selection, rectPaint); mCanvas.drawBitmap(bitmap, selection.right - 25, selection.bottom - 25, null); rectPos.set(selection.left, selection.top); mCanvas.restore(); } @Override public boolean onTouchEvent(MotionEvent event) { int eventaction = event.getAction(); switch (eventaction) { case MotionEvent.ACTION_DOWN: touchDown((int) event.getX(), (int) event.getY()); previous.set((int) event.getX(), (int) event.getY()); break; case MotionEvent.ACTION_MOVE: touchMove((int) event.getX(), (int) event.getY()); if (isActionInsideRectangle(event.getX(), event.getY()) && !isAffectedBottom) { drag((int) event.getX(), (int) event.getY()); invalidate(); // redraw rectangle previous.set((int) event.getX(), (int) event.getY()); } previous.set((int) event.getX(), (int) event.getY()); break; case MotionEvent.ACTION_UP: touchUp((int) event.getX(), (int) event.getY()); previous = new Point(); break; } return true; } private void initCropView() { paint.setColor(Color.WHITE); paint.setStyle(Style.STROKE); paint.setStrokeWidth(5); leftTop = new Point(); rightBottom = new Point(); center = new Point(); previous = new Point(); rectPos = new Point(); } public void resetPoints() { center.set(getWidth() / 2, getHeight() / 2); leftTop.set((getWidth() - initial_size) / 2, (getHeight() - initial_size) / 2); rightBottom.set(leftTop.x + initial_size, leftTop.y + initial_size); selection = new Rect(leftTop.x, leftTop.y, rightBottom.x, rightBottom.y); knobRect = new Rect(selection.right, selection.bottom, bitmap.getWidth(), bitmap.getHeight()); dest = selection; } private boolean isActionInsideRectangle(float x, float y) { int buffer = 10; return (x >= (selection.left) && x <= (selection.right) && y >= (selection.top) && y <= (selection.bottom)) ? true : false; } void touchDown(int x, int y) { System.out.println("selection " + selection); int dx = (previous.x - x) / 2; int dy = (previous.y - y) / 2; // d= rotation(dx,dy); currentPoint.set(x, y); if (pointsAreClose(x, y, selection.right, selection.bottom)) { isAffectedBottom = true; System.out.println("isAffectedBottom " + isAffectedBottom); } } void touchMove(int x, int y) { currentPoint.set(x, y); if (isAffectedBottom) { int dx = (previous.x - x) / 2; int dy = (previous.y - y) / 2; double startAngle = getAngle(previous.x, previous.y); double currentAngle = getAngle(x, y); matrix.postRotate((float) (startAngle - currentAngle), selection.width() / 2.0f, selection.height() / 2.0f); // selection.inset(dx, dy); invalidate(); } } void touchUp(int x, int y) { currentPoint.set(x, y); isAffectedBottom = false; } private boolean pointsAreClose(float x1, float y1, float x2, float y2) { return Math.hypot(x1 - x2, y1 - y2) < TOUCH_TOLERANCE; } private void drag(int x, int y) { int movement; movement = x - previous.x; int movementY = y - previous.y; selection.set(selection.left + movement, selection.top + movementY, selection.right + movement, selection.bottom + movementY); selection.sort(); invalidate(); } /** * Calculate the degree to be rotated by. * * @param event * @return Degrees */ // private float rotation(float dx, float dy) { // // // double delta_x = (dx); // // double delta_y = (dy); // double radians = Math.atan2((selection.left) - (previous.y), // (selection.top) - (previous.x)); // double radians2 = Math.atan2((selection.left) - (dy), // (selection.top) - (dx)); // // System.out.println("radians" + radians); // System.out.println("" + radians2); // System.out.println("radians2-radians" + (radians2 - radians)); // System.out.println(Math.toDegrees(radians2 - radians)); // return (float) Math.toDegrees(radians2 - radians); // // } private double getAngle(double xTouch, double yTouch) { double x = xTouch - (getWidth() / 2d); double y = getHeight() - yTouch - (getHeight() / 2d); switch (getQuadrant(x, y)) { case 1: System.out.println("1"); return Math.asin(y / Math.hypot(x, y)) * 180 / Math.PI; case 2: case 3: System.out.println("32"); return 180 - (Math.asin(y / Math.hypot(x, y)) * 180 / Math.PI); case 4: System.out.println("4"); return 360 + Math.asin(y / Math.hypot(x, y)) * 180 / Math.PI; default: // ignore, does not happen return 0; } } /** * @return The selected quadrant. */ private int getQuadrant(double x, double y) { if (x >= 0) { return y >= 0 ? 1 : 4; } else { return y >= 0 ? 2 : 3; } } } } 

Por favor revise el repositorio en github lo creo.

Cuente la distancia desde el punto central en la vista de giro y zoom hasta el punto de empuje. Solo usa :

  private float getDistance(Point a, Point b) { float v = ((ax - bx) * (ax - bx)) + ((ay - by) * (ay - by)); return ((int) (Math.sqrt(v) * 100)) / 100f; } 

Y contar el OA / OB que el valor puede contar la vista nueva altura y ancho

Contar el ángulo AOB, el A es el primer punto de empuje, el B es el último punto de movimiento, el O es el centro del punto de vista.

Y luego simplemente establecer nueva altura y ancho para la vista, y contar la izquierda y la parte superior para la vista.

Enlace de souce: https://github.com/ryanch741/android-view-rotate-zoom-single-finger

el código:

  Point pushPoint; int lastImgWidth; int lastImgHeight; int lastImgLeft; int lastImgTop; int lastImgAngle; double lastComAngle; int pushImgWidth; int pushImgHeight; int lastPushBtnLeft; int lastPushBtnTop; private View mView; private Point mViewCenter; private static final double PI = 3.14159265359; public PushBtnTouchListener(View mView) { this.mView = mView; } private FrameLayout.LayoutParams pushBtnLP; private FrameLayout.LayoutParams imgLP; float lastX = -1; float lastY = -1; @Override public boolean onTouch(View pushView, MotionEvent event) { switch (event.getAction() & MotionEvent.ACTION_MASK) { // 主点按下case MotionEvent.ACTION_DOWN: pushBtnLP = (FrameLayout.LayoutParams) pushView.getLayoutParams(); imgLP = (FrameLayout.LayoutParams) mView.getLayoutParams(); pushPoint = getPushPoint(pushBtnLP, event); lastImgWidth = imgLP.width; lastImgHeight = imgLP.height; lastImgLeft = imgLP.leftMargin; lastImgTop = imgLP.topMargin; lastImgAngle = (int) mView.getRotation(); lastPushBtnLeft = pushBtnLP.leftMargin; lastPushBtnTop = pushBtnLP.topMargin; pushImgWidth = pushBtnLP.width; pushImgHeight = pushBtnLP.height; lastX = event.getRawX(); lastY = event.getRawY(); refreshImageCenter(); break; // 副点按下case MotionEvent.ACTION_POINTER_DOWN: break; case MotionEvent.ACTION_UP: { break; } case MotionEvent.ACTION_POINTER_UP: break; case MotionEvent.ACTION_MOVE: float rawX = event.getRawX(); float rawY = event.getRawY(); if (lastX != -1) { if (Math.abs(rawX - lastX) < 5 && Math.abs(rawY - lastY) < 5) { return false; } } lastX = rawX; lastY = rawY; Point O = mViewCenter, A = pushPoint, B = getPushPoint(pushBtnLP, event); float dOA = getDistance(O, A); float dOB = getDistance(O, B); float f = dOB / dOA; int newWidth = (int) (lastImgWidth * f); int newHeight = (int) (lastImgHeight * f); imgLP.leftMargin = lastImgLeft - ((newWidth - lastImgWidth) / 2); imgLP.topMargin = lastImgTop - ((newHeight - lastImgHeight) / 2); imgLP.width = newWidth; imgLP.height = newHeight; mView.setLayoutParams(imgLP); float fz = (((Ax - Ox) * (Bx - Ox)) + ((Ay - Oy) * (By - Oy))); float fm = dOA * dOB; double comAngle = (180 * Math.acos(fz / fm) / PI); if (Double.isNaN(comAngle)) { comAngle = (lastComAngle < 90 || lastComAngle > 270) ? 0 : 180; } else if ((By - Oy) * (Ax - Ox) < (Ay - Oy) * (Bx - Ox)) { comAngle = 360 - comAngle; } lastComAngle = comAngle; float angle = (float) (lastImgAngle + comAngle); angle = angle % 360; mView.setRotation(angle); Point imageRB = new Point(mView.getLeft() + mView.getWidth(), mView.getTop() + mView.getHeight()); Point anglePoint = getAnglePoint(O, imageRB, angle); pushBtnLP.leftMargin = (int) (anglePoint.x - pushImgWidth / 2); pushBtnLP.topMargin = (int) (anglePoint.y - pushImgHeight / 2); pushView.setLayoutParams(pushBtnLP); break; } return false; } private void refreshImageCenter() { int x = mView.getLeft() + mView.getWidth() / 2; int y = mView.getTop() + mView.getHeight() / 2; mViewCenter = new Point(x, y); } private Point getPushPoint(FrameLayout.LayoutParams lp, MotionEvent event) { return new Point(lp.leftMargin + (int) event.getX(), lp.topMargin + (int) event.getY()); } private float getDistance(Point a, Point b) { float v = ((ax - bx) * (ax - bx)) + ((ay - by) * (ay - by)); return ((int) (Math.sqrt(v) * 100)) / 100f; } private Point getAnglePoint(Point O, Point A, float angle) { int x, y; float dOA = getDistance(O, A); double p1 = angle * PI / 180f; double p2 = Math.acos((Ax - Ox) / dOA); x = (int) (Ox + dOA * Math.cos(p1 + p2)); double p3 = Math.acos((Ax - Ox) / dOA); y = (int) (Oy + dOA * Math.sin(p1 + p3)); return new Point(x, y); } 

Tengo Diseño Un Diseño que puede funcionar como su necesidad. Descargar Demo aquí

Archivo Java

 import android.annotation.SuppressLint; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.ColorMatrixColorFilter; import android.graphics.Paint; import android.view.GestureDetector; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.RelativeLayout; public class ClipArt extends RelativeLayout { int baseh; int basew; int basex; int basey; ImageButton btndel; ImageButton btnrot; ImageButton btnscl; RelativeLayout clip; Context cntx; boolean freeze = false; int h; int i; ImageView image; String imageUri; boolean isShadow; int iv; RelativeLayout layBg; RelativeLayout layGroup; RelativeLayout.LayoutParams layoutParams; public LayoutInflater mInflater; int margl; int margt; float opacity = 1.0F; Bitmap originalBitmap; int pivx; int pivy; int pos; Bitmap shadowBitmap; float startDegree; String[] v; public ClipArt(Context paramContext) { super(paramContext); cntx = paramContext; layGroup = this; basex = 0; basey = 0; pivx = 0; pivy = 0; mInflater = ((LayoutInflater) paramContext.getSystemService("layout_inflater")); mInflater.inflate(R.layout.clipart, this, true); btndel = ((ImageButton) findViewById(R.id.del)); btnrot = ((ImageButton) findViewById(R.id.rotate)); btnscl = ((ImageButton) findViewById(R.id.sacle)); layoutParams = new RelativeLayout.LayoutParams(250, 250); layGroup.setLayoutParams(layoutParams); image = ((ImageView) findViewById(R.id.clipart)); image.setImageResource(R.drawable.ic_launcher); setOnTouchListener(new View.OnTouchListener() { final GestureDetector gestureDetector = new GestureDetector(ClipArt.this.cntx, new GestureDetector.SimpleOnGestureListener() { public boolean onDoubleTap(MotionEvent paramAnonymous2MotionEvent) { return false; } }); public boolean onTouch(View paramAnonymousView, MotionEvent event) { if (!ClipArt.this.freeze) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: layGroup.invalidate(); gestureDetector.onTouchEvent(event); layGroup.performClick(); basex = ((int) (event.getRawX() - layoutParams.leftMargin)); basey = ((int) (event.getRawY() - layoutParams.topMargin)); break; case MotionEvent.ACTION_MOVE: int i = (int) event.getRawX(); int j = (int) event.getRawY(); layBg = ((RelativeLayout) getParent()); if ((i - basex > -(layGroup.getWidth() * 2 / 3)) && (i - basex < layBg.getWidth() - layGroup.getWidth() / 3)) { layoutParams.leftMargin = (i - basex); } if ((j - basey > -(layGroup.getHeight() * 2 / 3)) && (j - basey < layBg.getHeight() - layGroup.getHeight() / 3)) { layoutParams.topMargin = (j - basey); } layoutParams.rightMargin = -1000; layoutParams.bottomMargin = -1000; layGroup.setLayoutParams(layoutParams); break; } return true; } return true; } }); this.btnscl.setOnTouchListener(new View.OnTouchListener() { @SuppressLint({ "NewApi" }) public boolean onTouch(View paramAnonymousView, MotionEvent event) { if (!ClipArt.this.freeze) { int j = (int) event.getRawX(); int i = (int) event.getRawY(); layoutParams = (RelativeLayout.LayoutParams) layGroup.getLayoutParams(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: ClipArt.this.layGroup.invalidate(); ClipArt.this.basex = j; ClipArt.this.basey = i; ClipArt.this.basew = ClipArt.this.layGroup.getWidth(); ClipArt.this.baseh = ClipArt.this.layGroup.getHeight(); int[] loaction = new int[2]; layGroup.getLocationOnScreen(loaction); margl = layoutParams.leftMargin; margt = layoutParams.topMargin; break; case MotionEvent.ACTION_MOVE: float f2 = (float) Math.toDegrees(Math.atan2(i - ClipArt.this.basey, j - ClipArt.this.basex)); float f1 = f2; if (f2 < 0.0F) { f1 = f2 + 360.0F; } j -= ClipArt.this.basex; int k = i - ClipArt.this.basey; i = (int) (Math.sqrt(j * j + k * k) * Math.cos(Math.toRadians(f1 - ClipArt.this.layGroup.getRotation()))); j = (int) (Math.sqrt(i * i + k * k) * Math.sin(Math.toRadians(f1 - ClipArt.this.layGroup.getRotation()))); k = i * 2 + ClipArt.this.basew; int m = j * 2 + ClipArt.this.baseh; if (k > 150) { layoutParams.width = k; layoutParams.leftMargin = (ClipArt.this.margl - i); } if (m > 150) { layoutParams.height = m; layoutParams.topMargin = (ClipArt.this.margt - j); } ClipArt.this.layGroup.setLayoutParams(layoutParams); ClipArt.this.layGroup.performLongClick(); break; } return true; } return ClipArt.this.freeze; } }); this.btnrot.setOnTouchListener(new View.OnTouchListener() { @SuppressLint({ "NewApi" }) public boolean onTouch(View paramAnonymousView, MotionEvent event) { if (!ClipArt.this.freeze) { layoutParams = (RelativeLayout.LayoutParams) ClipArt.this.layGroup.getLayoutParams(); ClipArt.this.layBg = ((RelativeLayout) ClipArt.this.getParent()); int[] arrayOfInt = new int[2]; layBg.getLocationOnScreen(arrayOfInt); int i = (int) event.getRawX() - arrayOfInt[0]; int j = (int) event.getRawY() - arrayOfInt[1]; switch (event.getAction()) { case MotionEvent.ACTION_DOWN: ClipArt.this.layGroup.invalidate(); ClipArt.this.startDegree = layGroup.getRotation(); ClipArt.this.pivx = (layoutParams.leftMargin + ClipArt.this.getWidth() / 2); ClipArt.this.pivy = (layoutParams.topMargin + ClipArt.this.getHeight() / 2); ClipArt.this.basex = (i - ClipArt.this.pivx); ClipArt.this.basey = (ClipArt.this.pivy - j); break; case MotionEvent.ACTION_MOVE: int k = ClipArt.this.pivx; int m = ClipArt.this.pivy; j = (int) (Math.toDegrees(Math.atan2(ClipArt.this.basey, ClipArt.this.basex)) - Math.toDegrees(Math.atan2(m - j, i - k))); i = j; if (j < 0) { i = j + 360; } ClipArt.this.layGroup.setRotation((ClipArt.this.startDegree + i) % 360.0F); break; } return true; } return ClipArt.this.freeze; } }); this.btndel.setOnClickListener(new View.OnClickListener() { public void onClick(View paramAnonymousView) { if (!ClipArt.this.freeze) { layBg = ((RelativeLayout) ClipArt.this.getParent()); layBg.performClick(); layBg.removeView(ClipArt.this.layGroup); } } }); } public void disableAll() { this.btndel.setVisibility(4); this.btnrot.setVisibility(4); this.btnscl.setVisibility(4); } public ImageView getImageView() { return this.image; } public void setFreeze(boolean paramBoolean) { this.freeze = paramBoolean; } } 

Archivo de diseño

 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <ImageButton android:id="@+id/rotate" android:layout_width="50dp" android:layout_height="50dp" android:layout_alignParentBottom="true" android:layout_alignParentLeft="true" android:adjustViewBounds="true" android:background="@android:color/transparent" android:scaleType="fitCenter" android:src="@drawable/rotation"/> <ImageButton android:id="@+id/sacle" android:layout_width="50dp" android:layout_height="50dp" android:layout_alignParentBottom="true" android:layout_alignParentRight="true" android:adjustViewBounds="true" android:background="@android:color/transparent" android:scaleType="fitCenter" android:src="@drawable/pointer"/> <ImageButton android:id="@+id/del" android:layout_width="50dp" android:layout_height="50dp" android:layout_alignParentRight="true" android:layout_alignParentTop="true" android:adjustViewBounds="true" android:background="@android:color/transparent" android:scaleType="fitCenter" android:src="@drawable/close"/> <ImageView android:id="@+id/clipart" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="10dp"/> </RelativeLayout> 

E imágenes puestas

Introduzca aquí la descripción de la imagen Introduzca aquí la descripción de la imagen Introduzca aquí la descripción de la imagen

Supongo que la rotación / escalado ocurre desde el centro de la imagen? En ese caso, es simple trigonometría para encontrar el ángulo de rotación y el tamaño:

Diagrama del triángulo formado entre el centro de la imagen y el dedo

Calcular dx y dy de las coordenadas del dedo menos las coordenadas del centro. Math.atan2(dy, dx) es el ángulo de rotación (en radianes) y Math.hypot(dx,dy) se puede utilizar para el tamaño relativo, o simplemente doblar el dx / dy y usar directamente.

Interesting Posts
FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.