我正在尝试开发一个自定义视图,该视图可以使用位于右下角的按钮(也可以用两根手指)旋转。
使用该链接https://github.com/ryanch741/android-view-rotate-zoom-single-finger
我正在尝试修改其自定义视图。为此,我使用了在该项目https://github.com/thuytrinh/android-collage-views
中创建的MultiTouchListener类,因此我可以使用按钮和两个手指。
但是当我使用两根手指时,我无法将按钮保持在右下角。我试图使用视图矩阵没有成功
那么在旋转,缩放和平移动作之后,如何计算imageView的新位置?
这是我的课程
class ViewOnTouchListener2 implements View.OnTouchListener {
private final static String LOG_TAG = ViewOnTouchListener2.class.getSimpleName();
Point pushPoint;
int lastImgLeft;
int lastImgTop;
FrameLayout.LayoutParams viewLP;
FrameLayout.LayoutParams pushBtnLP;
int lastPushBtnLeft;
int lastPushBtnTop;
private View mPushView;
RectF mRect;
/**/
private static final int INVALID_POINTER_ID = -1;
private int mActivePointerId = INVALID_POINTER_ID;
public boolean isRotateEnabled = true;
public boolean isTranslateEnabled = true;
public boolean isScaleEnabled = true;
public float minimumScale = 0.5f;
public float maximumScale = 10.0f;
private ScaleGestureDetector mScaleGestureDetector;
/**/
ViewOnTouchListener2(View mPushView) {
this.mPushView = mPushView;
mScaleGestureDetector = new ScaleGestureDetector(new ViewOnTouchListener2.ScaleGestureListener());
}
@Override
public boolean onTouch(View view, MotionEvent event) {
int pointerCount = event.getPointerCount();
mScaleGestureDetector.onTouchEvent(view, event);
int action = event.getAction();
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
if (null == viewLP) {
viewLP = (FrameLayout.LayoutParams) view.getLayoutParams();
}
if (null == pushBtnLP) {
pushBtnLP = (FrameLayout.LayoutParams) mPushView.getLayoutParams();
}
// Save the ID of this pointer.
mActivePointerId = event.getPointerId(0);
//pushPoint = getRawPoint(event);
pushPoint = getRawPoint(event,mActivePointerId,viewLP);
//Log.d(LOG_TAG," pushPoint x "+pushPoint.x);
//Log.d(LOG_TAG," pushPoint y "+pushPoint.y);
lastImgLeft = viewLP.leftMargin;
lastImgTop = viewLP.topMargin;
//mRect = new RectF (viewLP.leftMargin, viewLP.topMargin, viewLP.rightMargin, viewLP.bottomMargin);
//mRect = new RectF (viewLP.leftMargin, viewLP.topMargin, viewLP.rightMargin, viewLP.bottomMargin);
Log.d(LOG_TAG," lastImgLeft "+lastImgLeft);
Log.d(LOG_TAG," lastImgTop "+lastImgTop);
lastPushBtnLeft = pushBtnLP.leftMargin;
lastPushBtnTop = pushBtnLP.topMargin;
break;
case MotionEvent.ACTION_MOVE:
//un seul doigt
int pointerIndex = event.findPointerIndex(mActivePointerId);
if (pointerIndex != -1) {
//Point newPoint = getRawPoint(event);
Point newPoint = getRawPoint(event,pointerIndex,viewLP);
float moveX = newPoint.x - pushPoint.x;
float moveY = newPoint.y - pushPoint.y;
if (!mScaleGestureDetector.isInProgress()) {
viewLP.leftMargin = (int) (lastImgLeft + moveX);
viewLP.topMargin = (int) (lastImgTop + moveY);
view.setLayoutParams(viewLP);
pushBtnLP.leftMargin = (int) (lastPushBtnLeft + moveX);
pushBtnLP.topMargin = (int) (lastPushBtnTop + moveY);
mPushView.setLayoutParams(pushBtnLP);
}
}
break;
case MotionEvent.ACTION_CANCEL:
mActivePointerId = INVALID_POINTER_ID;
break;
case MotionEvent.ACTION_UP:
mActivePointerId = INVALID_POINTER_ID;
break;
case MotionEvent.ACTION_POINTER_UP: {
// Extract the index of the pointer that left the touch sensor.
int pointerIndex2 = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
int pointerId = event.getPointerId(pointerIndex2);
if (pointerId == mActivePointerId) {
// This was our active pointer going up. Choose a new
// active pointer and adjust accordingly.
int newPointerIndex = pointerIndex2 == 0 ? 1 : 0;
//mPrevX = event.getX(newPointerIndex);
//mPrevY = event.getY(newPointerIndex);
pushPoint = getRawPoint(event,newPointerIndex,viewLP);
lastImgLeft = viewLP.leftMargin;
lastImgTop = viewLP.topMargin;
lastPushBtnLeft = pushBtnLP.leftMargin;
lastPushBtnTop = pushBtnLP.topMargin;
mActivePointerId = event.getPointerId(newPointerIndex);
}
}
break;
}
return false;
}
private Point getRawPoint(MotionEvent event) {
//Log.d(LOG_TAG,"event.getRawX() : "+event.getRawX());
//Log.d(LOG_TAG,"event.getRawY() : "+event.getRawY());
return new Point((int) event.getRawX(), (int) event.getRawY());
}
private Point getRawPoint(MotionEvent event,int pointerIndex,FrameLayout.LayoutParams viewLp) {
//Log.d(LOG_TAG,"event.getRawX() ajusté : "+(viewLp.leftMargin + (int) event.getX(pointerIndex)));
//Log.d(LOG_TAG,"event.getRawY() ajusté : "+(viewLp.topMargin+ (int) event.getY(pointerIndex)));
return new Point(viewLp.leftMargin + (int) event.getX(pointerIndex),
viewLp.topMargin+ (int) event.getY(pointerIndex));
}
private class ScaleGestureListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
private float mPivotX;
private float mPivotY;
private Vector2D mPrevSpanVector = new Vector2D();
@Override
public boolean onScaleBegin(View view, ScaleGestureDetector detector) {
mPivotX = detector.getFocusX();
mPivotY = detector.getFocusY();
mPrevSpanVector.set(detector.getCurrentSpanVector());
return true;
}
@Override
public boolean onScale(View view, ScaleGestureDetector detector) {
ViewOnTouchListener2.TransformInfo info = new ViewOnTouchListener2.TransformInfo();
info.deltaScale = isScaleEnabled ? detector.getScaleFactor() : 1.0f;
info.deltaAngle = isRotateEnabled ? Vector2D.getAngle(mPrevSpanVector, detector.getCurrentSpanVector()) : 0.0f;
info.deltaX = isTranslateEnabled ? detector.getFocusX() - mPivotX : 0.0f;
info.deltaY = isTranslateEnabled ? detector.getFocusY() - mPivotY : 0.0f;
info.pivotX = mPivotX;
info.pivotY = mPivotY;
info.minimumScale = minimumScale;
info.maximumScale = maximumScale;
move(view, info);
return false;
}
}
private void move(View view, ViewOnTouchListener2.TransformInfo info) {
computeRenderOffset(view, info.pivotX, info.pivotY);
adjustTranslation(view, info.deltaX, info.deltaY);
// Assume that scaling still maintains aspect ratio.
float scale = view.getScaleX() * info.deltaScale;
scale = Math.max(info.minimumScale, Math.min(info.maximumScale, scale));
view.setScaleX(scale);
view.setScaleY(scale);
//Log.d(LOG_TAG,"scale : "+scale);
float rotation = adjustAngle(view.getRotation() + info.deltaAngle);
view.setRotation(rotation);
}
private void setPushButton(View view,TransformInfo info,float rotation){
float[] prevPoint = {0.0f, 0.0f};
view.getMatrix().mapPoints(prevPoint);
view.setPivotX(info.pivotX);
view.setPivotY(info.pivotY);
float[] currPoint = {0.0f, 0.0f};
view.getMatrix().mapPoints(currPoint);
float offsetX = currPoint[0] - prevPoint[0];
float offsetY = currPoint[1] - prevPoint[1];
//view.setTranslationX(view.getTranslationX() - offsetX);
//view.setTranslationY(view.getTranslationY() - offsetY);
//Point newPushButtonPosition = getPositionOfPushButton(view,(FrameLayout.LayoutParams) view.getLayoutParams());
//Log.d(LOG_TAG," new x "+currPoint[0]);
//Log.d(LOG_TAG," new y "+currPoint[1]);
pushBtnLP.leftMargin = (int)(view.getTranslationX());
pushBtnLP.topMargin = (int)(view.getTranslationY());
mPushView.setLayoutParams(pushBtnLP);
}
private Point getPositionOfPushButton(View view,FrameLayout.LayoutParams layoutParams){
//Log.d(LOG_TAG," layoutParams.leftMargin x "+layoutParams.leftMargin);
//Log.d(LOG_TAG," layoutParams.topMargin y "+layoutParams.topMargin);
//Log.d(LOG_TAG," width : "+view.getWidth()*view.getScaleX());
//Log.d(LOG_TAG," getHeight : "+view.getHeight()*view.getScaleY());
return new Point(layoutParams.leftMargin+ view.getWidth()*view.getScaleX(),
layoutParams.topMargin+view.getHeight()*view.getScaleY());
}
private static void adjustTranslation(View view, float deltaX, float deltaY) {
float[] deltaVector = {deltaX, deltaY};
view.getMatrix().mapVectors(deltaVector);
view.setTranslationX(view.getTranslationX() + deltaVector[0]);
view.setTranslationY(view.getTranslationY() + deltaVector[1]);
}
private static void computeRenderOffset(View view, float pivotX, float pivotY) {
if (view.getPivotX() == pivotX && view.getPivotY() == pivotY) {
return;
}
float[] prevPoint = {0.0f, 0.0f};
view.getMatrix().mapPoints(prevPoint);
view.setPivotX(pivotX);
view.setPivotY(pivotY);
float[] currPoint = {0.0f, 0.0f};
view.getMatrix().mapPoints(currPoint);
float offsetX = currPoint[0] - prevPoint[0];
float offsetY = currPoint[1] - prevPoint[1];
view.setTranslationX(view.getTranslationX() - offsetX);
view.setTranslationY(view.getTranslationY() - offsetY);
}
private static float adjustAngle(float degrees) {
if (degrees > 180.0f) {
degrees -= 360.0f;
} else if (degrees < -180.0f) {
degrees += 360.0f;
}
return degrees;
}
private class TransformInfo {
public float deltaX;
public float deltaY;
public float deltaScale;
public float deltaAngle;
public float pivotX;
public float pivotY;
public float minimumScale;
public float maximumScale;
}
}