我正在开发一款应用程序,其功能是通过拖动右下角按钮来调整和旋转图像视图。
我看到一个应用程序的功能,如果我们拖动右下角按钮对角线imageview大小已调整大小,否则如果我们拖动按钮左侧或右侧方向imageview已按方向旋转。我希望在我的应用中实现此功能
我正在努力实现单指旋转以及调整图像视图的大小。
请以正确的方式指导我。
我正在尝试此代码,并尝试应用缩放和旋转,但无法做到请帮助我。 belove代码进行缩放和旋转手指基础动作。
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;
}
}
}
}
答案 0 :(得分:7)
我有一个可以根据需要设计的布局。 下载演示here
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;
}
}
布局文件
<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>
和图像放在可绘制的
答案 1 :(得分:6)
请检查github中的存储库我创建它。
计算旋转和缩放视图中心点到推送点的距离。 只需使用:
private float getDistance(Point a, Point b) {
float v = ((a.x - b.x) * (a.x - b.x)) + ((a.y - b.y) * (a.y - b.y));
return ((int) (Math.sqrt(v) * 100)) / 100f;
}
并计算OA / OB,该值可以计算视图的新高度和宽度
计算角度AOB,A是第一个推动点,B是最后一个移动点,O是视点的中心。
然后只为视图设置新的高度和宽度,并计算左侧和顶部的视图。
源链接:https://github.com/ryanch741/android-view-rotate-zoom-single-finger
代码:
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 = (((A.x - O.x) * (B.x - O.x)) + ((A.y - O.y) * (B.y - O.y)));
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 ((B.y - O.y) * (A.x - O.x) < (A.y - O.y) * (B.x - O.x)) {
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 = ((a.x - b.x) * (a.x - b.x)) + ((a.y - b.y) * (a.y - b.y));
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((A.x - O.x) / dOA);
x = (int) (O.x + dOA * Math.cos(p1 + p2));
double p3 = Math.acos((A.x - O.x) / dOA);
y = (int) (O.y + dOA * Math.sin(p1 + p3));
return new Point(x, y);
}
答案 2 :(得分:1)
我假设从图像中心发生旋转/缩放?在这种情况下,找到旋转角度和大小是简单的三角函数:
计算手指坐标的dx
和dy
减去中心坐标。 Math.atan2(dy, dx)
是旋转角度(以弧度表示),Math.hypot(dx,dy)
可用于相对大小,或者只是dx / dy的两倍并直接使用。