Android 可以用一个或两个手指旋转和缩放的自定义图像视图

Android 可以用一个或两个手指旋转和缩放的自定义图像视图,android,Android,我正在尝试开发一个自定义视图,它可以使用位于右下角的按钮以及两个手指进行旋转 使用该链接 我正在尝试修改它的自定义视图。为此,我使用了在该项目中创建的类MultiTouchListener 这样我就可以用按钮和两个手指了 但是当我用两个手指时,我不能保持按钮在右下角。我试图使用视图的矩阵,但没有成功 那么,在旋转、缩放和平移操作之后,如何计算imageView的新位置呢 这是我的班级 class ViewOnTouchListener2 implements View.OnTouchListen

我正在尝试开发一个自定义视图,它可以使用位于右下角的按钮以及两个手指进行旋转

使用该链接

我正在尝试修改它的自定义视图。为此,我使用了在该项目中创建的类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;
}
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