Android 可以用一个或两个手指旋转和缩放的自定义图像视图
我正在尝试开发一个自定义视图,它可以使用位于右下角的按钮以及两个手指进行旋转 使用该链接 我正在尝试修改它的自定义视图。为此,我使用了在该项目中创建的类MultiTouchListener 这样我就可以用按钮和两个手指了 但是当我用两个手指时,我不能保持按钮在右下角。我试图使用视图的矩阵,但没有成功 那么,在旋转、缩放和平移操作之后,如何计算imageView的新位置呢 这是我的班级Android 可以用一个或两个手指旋转和缩放的自定义图像视图,android,Android,我正在尝试开发一个自定义视图,它可以使用位于右下角的按钮以及两个手指进行旋转 使用该链接 我正在尝试修改它的自定义视图。为此,我使用了在该项目中创建的类MultiTouchListener 这样我就可以用按钮和两个手指了 但是当我用两个手指时,我不能保持按钮在右下角。我试图使用视图的矩阵,但没有成功 那么,在旋转、缩放和平移操作之后,如何计算imageView的新位置呢 这是我的班级 class ViewOnTouchListener2 implements View.OnTouchListen
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;
}
class ViewOnTouchListener2实现View.OnTouchListener{
私有最终静态字符串LOG_TAG=ViewOnTouchListener2.class.getSimpleName();
点推点;
内拉斯廷格勒夫特;
int lastImgTop;
FrameLayout.LayoutParams viewLP;
FrameLayout.LayoutParams pushBtnLP;
int lastPushBtnLeft;
int lastPushBtnTop;
私有视图;
RectF-mRect;
/**/
私有静态final int无效\u指针\u ID=-1;
private int mActivePointerId=无效的\u指针\u ID;
公共布尔值isRotateEnabled=true;
公共布尔值isTranslateEnabled=true;
公共布尔值isScaleEnabled=true;
公共浮标最小刻度=0.5f;
公共浮动最大刻度=10.0f;
专用标尺检测器mScaleGestureDetector;
/**/
ViewOnTouchListener2(视图mPushView){
this.mPushView=mPushView;
mScaleGestureDetector=new scalegestruedetector(new ViewOnTouchListener2.scalegestrueListener());
}
@凌驾
公共布尔onTouch(视图、运动事件){
int pointerCount=event.getPointerCount();
mScaleGestureDetector.onTouchEvent(视图、事件);
int action=event.getAction();
开关(event.getAction()&MotionEvent.ACTION\u掩码){
case MotionEvent.ACTION\u DOWN:
如果(null==viewLP){
viewLP=(FrameLayout.LayoutParams)view.getLayoutParams();
}
如果(null==pushBtnLP){
pushBtnLP=(FrameLayout.LayoutParams)mPushView.getLayoutParams();
}
//保存此指针的ID。
MacTivePointId=event.getPointerId(0);
//pushPoint=getRawPoint(事件);
pushPoint=getRawPoint(事件、MacTivePointId、viewLP);
//日志d(日志标签,“推点x”+推点x);
//日志d(日志标签,“推点y”+推点y);
lastImgLeft=viewLP.leftMargin;
lastImgTop=viewLP.topMargin;
//mRect=新的RectF(viewLP.leftMargin、viewLP.topMargin、viewLP.righmargin、viewLP.bottomMargin);
//mRect=新的RectF(viewLP.leftMargin、viewLP.topMargin、viewLP.righmargin、viewLP.bottomMargin);
Log.d(日志标签“lastImgLeft”+lastImgLeft);
Log.d(日志标签“lastImgTop”+lastImgTop);
lastPushBtnLeft=pushBtnLP.leftMargin;
lastPushBtnTop=pushBtnLP.topMargin;
打破
case MotionEvent.ACTION\u移动:
//乌瑟尔多伊格特酒店
int pointerIndex=event.findPointerIndex(MacTivePointInterId);
如果(指针索引!=-1){
//点newPoint=getRawPoint(事件);
Point newPoint=getRawPoint(事件、pointerIndex、viewLP);
float moveX=newPoint.x-pushPoint.x;
float moveY=newPoint.y-pushPoint.y;
如果(!mScaleGestureDetector.isInProgress()){
viewLP.leftMargin=(int)(lastImgLeft+moveX);
viewLP.topMargin=(int)(lastImgTop+moveY);
view.setLayoutParams(viewLP);
pushBtnLP.leftMargin=(int)(lastPushBtnLeft+moveX);
pushBtnLP.topMargin=(int)(最后一次pushbtntop+moveY);
设置布局参数(pushBtnLP);
}
}
打破
case MotionEvent.ACTION\u取消:
MacTivePointId=无效的\u指针\u ID;
打破
case MotionEvent.ACTION\u UP:
MacTivePointId=无效的\u指针\u ID;
打破
case MotionEvent.ACTION\u指针\u向上:{
//提取离开触摸传感器的指针的索引。
int pointerIndex2=(action&MotionEvent.action\u POINTER\u INDEX\u MASK)>>MotionEvent.action\u POINTER\u INDEX\u SHIFT;
int pointerId=event.getPointerId(pointerIndex2);
if(pointerId==MacTivePointId){
//这是我们的活动指针上升。请选择一个新指针
//激活指针并进行相应调整。
int newPointerIndex=pointerIndex2==0?1:0;
//mPrevX=event.getX(newPointerIndex);
//mPrevY=event.getY(newPointerIndex);
pushPoint=getRawPoint(事件、newPointerIndex、viewLP);
lastImgLeft=viewLP.leftMargin;
lastImgTop=viewLP.topMargin;
lastPushBtnLeft=pushBtnLP.leftMargin;
lastPushBtnTop=pushBtnLP.topMargin;
MacTivePointId=event.getPointerId(newPointerIndex);
}
}
打破
}
返回false;
}
私有点getRawPoint(运动事件){
//Log.d(Log_标记,“event.getRawX():”+event.getRawX());
//Log.d(Log_标记,“event.getRawY():”+event.getRawY());
返回新点((int)event.getRawX(),(int)event.getRawY());
}
私有点getRawPoint(MotionEvent事件,int pointerIndex,FrameLayout.LayoutParams viewLp){
//Log.d(Log_标记,“event.getRawX()ajusté:”+(viewLp.leftMargin+(int)event.getX(pointerIndex));
//Log.d(Log_标记,“event.getRawY()ajusté:”+(viewLp.topMargin+(int)event.getY(pointerIndex));
返回新点(viewLp.leftMargin+(int)event.getX(pointerIndex),
topMargin+(int)event.getY(pointerIndex));
}
私有类scalegstruelistener扩展了scalegstruedetector.SimpleOnScalegstruelistener{
私人f