缩放和平移ImageView的安卓 [英] Zoom and Panning ImageView Android

查看:273
本文介绍了缩放和平移ImageView的安卓的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建了一个缩放和平移类的ImageView的。

特点我想创建。 - 这平底锅上单指触摸和移动 - 它放大,并在两个手指触摸和移动盘

在大多数情况下这工作得非常好。 它当我做了以下的轻微错误: - 我平移用一个手指(状态:没问题) - 我放下第二根手指,缩放和平移(状态:没问题) - 我释放我的第二个手指(状态:图像跳转一点)

希望有人能帮助我解决这个问题。

我在想,它必须做复位mLastTouchX和mLastTouchY在案例MotionEvent.ACTION_POINTER_UP

任何帮助将大大AP preciated!

 进口android.content.Context;
进口android.graphics.Canvas;
进口android.util.AttributeSet;
进口android.util.Log;
进口android.view.MotionEvent;
进口android.view.ScaleGestureDetector;
进口android.widget.ImageView;

公共类MyImageView扩展ImageView的{

    私有静态最终诠释INVALID_POINTER_ID = -1;

    私人浮动mPosX;
    私人浮动mPosY;

    私人浮动mLastTouchX;
    私人浮动mLastTouchY;
    私人浮动mLastGestureX;
    私人浮动mLastGestureY;
    私人诠释mActivePointerId = INVALID_POINTER_ID;

    私人ScaleGestureDetector mScaleDetector;
    私人浮动mScaleFactor = 1.F;

    公共MyImageView(上下文的背景下,ATTRS的AttributeSet){
        这(背景下,ATTRS,0);
        mScaleDetector =新ScaleGestureDetector(的getContext(),新ScaleListener());
    }

    公共MyImageView(上下文的背景下,ATTRS的AttributeSet,诠释defStyle){
        超(背景下,ATTRS,defStyle);
        mScaleDetector =新ScaleGestureDetector(上下文,新ScaleListener());
    }

    @覆盖
    公共布尔的onTouchEvent(MotionEvent EV){
        //让ScaleGestureDetector检查所有事件。
        mScaleDetector.onTouchEvent(EV);

        最终诠释行动= ev.getAction();
        开关(行动及放大器; MotionEvent.ACTION_MASK){
            案例MotionEvent.ACTION_DOWN:{
                如果(!mScaleDetector.isInProgress()){
                    最终浮动X = ev.getX();
                    最终浮动Y = ev.getY();

                    mLastTouchX = X;
                    mLastTouchY = Y;
                    mActivePointerId = ev.getPointerId(0);
                }
                打破;
            }
            案例MotionEvent.ACTION_POINTER_1_DOWN:{
                如果(mScaleDetector.isInProgress()){
                    最终浮动GX = mScaleDetector.getFocusX();
                    最终浮动GY = mScaleDetector.getFocusY();
                    mLastGestureX = GX;
                    mLastGestureY = GY;
                }
                打破;
            }
            案例MotionEvent.ACTION_MOVE:{

                //只有当ScaleGestureDetector没有正在处理手势移动。
                如果(!mScaleDetector.isInProgress()){
                    最终诠释pointerIndex = ev.findPointerIndex(mActivePointerId);
                    最终浮动X = ev.getX(pointerIndex);
                    最终浮动Y = ev.getY(pointerIndex);

                    最终浮动DX = X  -  mLastTouchX;
                    最终浮动DY = Y  -  mLastTouchY;

                    mPosX + = DX;
                    mPosY + = DY;

                    无效();

                    mLastTouchX = X;
                    mLastTouchY = Y;
                }
                其他{
                    最终浮动GX = mScaleDetector.getFocusX();
                    最终浮动GY = mScaleDetector.getFocusY();

                    最终浮动GDX = GX  -  mLastGestureX;
                    最终浮动GDY = GY  -  mLastGestureY;

                    mPosX + = GDX;
                    mPosY + = GDY;

                    无效();

                    mLastGestureX = GX;
                    mLastGestureY = GY;
                }

                打破;
            }
            案例MotionEvent.ACTION_UP:{
                mActivePointerId = INVALID_POINTER_ID;
                打破;
            }
            案例MotionEvent.ACTION_CANCEL:{
                mActivePointerId = INVALID_POINTER_ID;
                打破;
            }
            案例MotionEvent.ACTION_POINTER_UP:{
                最终诠释pointerIndex =(ev.getAction()及MotionEvent.ACTION_POINTER_INDEX_MASK)
                        >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
                最终诠释pointerId = ev.getPointerId(pointerIndex);
                如果(pointerId == mActivePointerId){
                    Log.d(调试,mActivePointerId);
                    //这是我们主动指针往上走。选择一个新的
                    //活跃的指针和相应的调整。
                    最终诠释newPointerIndex = pointerIndex == 0? 1:0;
                    mLastTouchX = ev.getX(newPointerIndex);
                    mLastTouchY = ev.getY(newPointerIndex);
                    mActivePointerId = ev.getPointerId(newPointerIndex);
                }

                打破;
            }
        }

        返回true;
    }

    @覆盖
    公共无效的OnDraw(帆布油画){

        canvas.save();

        canvas.translate(mPosX,mPosY);

        如果(mScaleDetector.isInProgress()){
            canvas.scale(mScaleFactor,mScaleFactor,mScaleDetector.getFocusX(),mScaleDetector.getFocusY());
        }
        其他{
            canvas.scale(mScaleFactor,mScaleFactor);
        }
        super.onDraw(画布);
        canvas.restore();
    }

    私有类ScaleListener扩展ScaleGestureDetector.SimpleOnScaleGestureListener {
        @覆盖
        公共布尔onScale(ScaleGestureDetector检测器){
            mScaleFactor * = detector.getScaleFactor();

            //不要让物体得到过小或过大。
            mScaleFactor = Math.max(0.1F,Math.min(mScaleFactor,10.0f));

            无效();
            返回true;
        }
    }
}
 

解决方案

看来canvas.scale()在OnDraw中方法别人的语句所需的mLastGestureX和mLastGestureY停止跳动。 我也刷新mLastTouchX和mLastTouchY去当回单指平移的案例MotionEvent.ACTION_POINTER_UP

下面是最终的,可能不适合每个人都导致它不限制平移过去的图像边界,但应该是很容易实现,也有很多讨论,在那里上的话题。

 进口android.content.Context;
进口android.graphics.Canvas;
进口android.util.AttributeSet;
进口android.view.MotionEvent;
进口android.view.ScaleGestureDetector;
进口android.widget.ImageView;

公共类MyImageView扩展ImageView的{

    私有静态最终诠释INVALID_POINTER_ID = -1;

    私人浮动mPosX;
    私人浮动mPosY;

    私人浮动mLastTouchX;
    私人浮动mLastTouchY;
    私人浮动mLastGestureX;
    私人浮动mLastGestureY;
    私人诠释mActivePointerId = INVALID_POINTER_ID;

    私人ScaleGestureDetector mScaleDetector;
    私人浮动mScaleFactor = 1.F;

    公共MyImageView(上下文的背景下,ATTRS的AttributeSet){
        这(背景下,ATTRS,0);
        mScaleDetector =新ScaleGestureDetector(的getContext(),新ScaleListener());
    }

    公共MyImageView(上下文的背景下,ATTRS的AttributeSet,诠释defStyle){
        超(背景下,ATTRS,defStyle);
        mScaleDetector =新ScaleGestureDetector(上下文,新ScaleListener());
    }

    @覆盖
    公共布尔的onTouchEvent(MotionEvent EV){
        //让ScaleGestureDetector检查所有事件。
        mScaleDetector.onTouchEvent(EV);

        最终诠释行动= ev.getAction();
        开关(行动及放大器; MotionEvent.ACTION_MASK){
            案例MotionEvent.ACTION_DOWN:{
                如果(!mScaleDetector.isInProgress()){
                    最终浮动X = ev.getX();
                    最终浮动Y = ev.getY();

                    mLastTouchX = X;
                    mLastTouchY = Y;
                    mActivePointerId = ev.getPointerId(0);
                }
                打破;
            }
            案例MotionEvent.ACTION_POINTER_1_DOWN:{
                如果(mScaleDetector.isInProgress()){
                    最终浮动GX = mScaleDetector.getFocusX();
                    最终浮动GY = mScaleDetector.getFocusY();
                    mLastGestureX = GX;
                    mLastGestureY = GY;
                }
                打破;
            }
            案例MotionEvent.ACTION_MOVE:{

                //只有当ScaleGestureDetector没有正在处理手势移动。
                如果(!mScaleDetector.isInProgress()){
                    最终诠释pointerIndex = ev.findPointerIndex(mActivePointerId);
                    最终浮动X = ev.getX(pointerIndex);
                    最终浮动Y = ev.getY(pointerIndex);

                    最终浮动DX = X  -  mLastTouchX;
                    最终浮动DY = Y  -  mLastTouchY;

                    mPosX + = DX;
                    mPosY + = DY;

                    无效();

                    mLastTouchX = X;
                    mLastTouchY = Y;
                }
                其他{
                    最终浮动GX = mScaleDetector.getFocusX();
                    最终浮动GY = mScaleDetector.getFocusY();

                    最终浮动GDX = GX  -  mLastGestureX;
                    最终浮动GDY = GY  -  mLastGestureY;

                    mPosX + = GDX;
                    mPosY + = GDY;

                    无效();

                    mLastGestureX = GX;
                    mLastGestureY = GY;
                }

                打破;
            }
            案例MotionEvent.ACTION_UP:{
                mActivePointerId = INVALID_POINTER_ID;
                打破;
            }
            案例MotionEvent.ACTION_CANCEL:{
                mActivePointerId = INVALID_POINTER_ID;
                打破;
            }
            案例MotionEvent.ACTION_POINTER_UP:{

                最终诠释pointerIndex =(ev.getAction()及MotionEvent.ACTION_POINTER_INDEX_MASK)
                        >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
                最终诠释pointerId = ev.getPointerId(pointerIndex);
                如果(pointerId == mActivePointerId){
                    //这是我们主动指针往上走。选择一个新的
                    //活跃的指针和相应的调整。
                    最终诠释newPointerIndex = pointerIndex == 0? 1:0;
                    mLastTouchX = ev.getX(newPointerIndex);
                    mLastTouchY = ev.getY(newPointerIndex);
                    mActivePointerId = ev.getPointerId(newPointerIndex);
                }
                其他{
                    最终诠释tempPointerIndex = ev.findPointerIndex(mActivePointerId);
                    mLastTouchX = ev.getX(tempPointerIndex);
                    mLastTouchY = ev.getY(tempPointerIndex);
                }

                打破;
            }
        }

        返回true;
    }

    @覆盖
    公共无效的OnDraw(帆布油画){

        canvas.save();

        canvas.translate(mPosX,mPosY);

        如果(mScaleDetector.isInProgress()){
            canvas.scale(mScaleFactor,mScaleFactor,mScaleDetector.getFocusX(),mScaleDetector.getFocusY());
        }
        其他{
            canvas.scale(mScaleFactor,mScaleFactor,mLastGestureX,mLastGestureY);
        }
        super.onDraw(画布);
        canvas.restore();
    }

    私有类ScaleListener扩展ScaleGestureDetector.SimpleOnScaleGestureListener {
        @覆盖
        公共布尔onScale(ScaleGestureDetector检测器){
            mScaleFactor * = detector.getScaleFactor();

            //不要让物体得到过小或过大。
            mScaleFactor = Math.max(0.1F,Math.min(mScaleFactor,10.0f));

            无效();
            返回true;
        }
    }
}
 

I have created a zoom and pan class for an ImageView.

Features I am trying to create. - It pans on single finger touch and movement - It zooms and pans on two finger touch and movement

For the most part this works very well. It has a slight bug when I do the following: - I pan around with one finger (Status: No problem) - I put down a second finger, zoom and pan (Status: No problem) - I release my second finger (Status: The image jumps a little)

Was hoping someone could help me solve this.

I am thinking that it must have to do with resetting the mLastTouchX and mLastTouchY in "case MotionEvent.ACTION_POINTER_UP"

Any help would greatly be appreciated!

import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.widget.ImageView;

public class MyImageView extends ImageView {

    private static final int INVALID_POINTER_ID = -1;

    private float mPosX;
    private float mPosY;

    private float mLastTouchX;
    private float mLastTouchY;
    private float mLastGestureX;
    private float mLastGestureY;
    private int mActivePointerId = INVALID_POINTER_ID;

    private ScaleGestureDetector mScaleDetector;
    private float mScaleFactor = 1.f;

    public MyImageView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
        mScaleDetector = new ScaleGestureDetector(getContext(), new ScaleListener());
    }

    public MyImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        // Let the ScaleGestureDetector inspect all events.
        mScaleDetector.onTouchEvent(ev);

        final int action = ev.getAction();
        switch (action & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN: {
                if (!mScaleDetector.isInProgress()) {
                    final float x = ev.getX();
                    final float y = ev.getY();

                    mLastTouchX = x;
                    mLastTouchY = y;
                    mActivePointerId = ev.getPointerId(0);
                }
                break;
            }
            case MotionEvent.ACTION_POINTER_1_DOWN: {
                if (mScaleDetector.isInProgress()) {
                    final float gx = mScaleDetector.getFocusX();
                    final float gy = mScaleDetector.getFocusY();
                    mLastGestureX = gx;
                    mLastGestureY = gy;
                }
                break;
            }
            case MotionEvent.ACTION_MOVE: {

                // Only move if the ScaleGestureDetector isn't processing a gesture.
                if (!mScaleDetector.isInProgress()) {
                    final int pointerIndex = ev.findPointerIndex(mActivePointerId);
                    final float x = ev.getX(pointerIndex);
                    final float y = ev.getY(pointerIndex);

                    final float dx = x - mLastTouchX;
                    final float dy = y - mLastTouchY;

                    mPosX += dx;
                    mPosY += dy;

                    invalidate();

                    mLastTouchX = x;
                    mLastTouchY = y;
                }
                else{
                    final float gx = mScaleDetector.getFocusX();
                    final float gy = mScaleDetector.getFocusY();

                    final float gdx = gx - mLastGestureX;
                    final float gdy = gy - mLastGestureY;

                    mPosX += gdx;
                    mPosY += gdy;

                    invalidate();

                    mLastGestureX = gx;
                    mLastGestureY = gy;
                }

                break;
            }
            case MotionEvent.ACTION_UP: {
                mActivePointerId = INVALID_POINTER_ID;
                break;
            }
            case MotionEvent.ACTION_CANCEL: {
                mActivePointerId = INVALID_POINTER_ID;
                break;
            }
            case MotionEvent.ACTION_POINTER_UP: {
                final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) 
                        >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
                final int pointerId = ev.getPointerId(pointerIndex);
                if (pointerId == mActivePointerId) {
                    Log.d("DEBUG", "mActivePointerId");
                    // This was our active pointer going up. Choose a new
                    // active pointer and adjust accordingly.
                    final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
                    mLastTouchX = ev.getX(newPointerIndex);
                    mLastTouchY = ev.getY(newPointerIndex);
                    mActivePointerId = ev.getPointerId(newPointerIndex);
                }

                break;
            }
        }

        return true;
    }

    @Override
    public void onDraw(Canvas canvas) {

        canvas.save();

        canvas.translate(mPosX, mPosY);

        if (mScaleDetector.isInProgress()) {
            canvas.scale(mScaleFactor, mScaleFactor, mScaleDetector.getFocusX(), mScaleDetector.getFocusY());
        }
        else{
            canvas.scale(mScaleFactor, mScaleFactor);
        }
        super.onDraw(canvas);
        canvas.restore();
    }

    private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
        @Override
        public boolean onScale(ScaleGestureDetector detector) {
            mScaleFactor *= detector.getScaleFactor();

            // Don't let the object get too small or too large.
            mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 10.0f));

            invalidate();
            return true;
        }
    }
}

解决方案

Seems the canvas.scale() in the 'else' statement of the 'onDraw' method required the mLastGestureX and mLastGestureY to stop the jumping. I also refresh mLastTouchX and mLastTouchY when going back to single finger panning in the 'case MotionEvent.ACTION_POINTER_UP'

Here's the final, may not suit everyone causes it does not restrict panning past image bounds but that should be easy to accomplish, there are alot of discussions out there on that topic.

import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.widget.ImageView;

public class MyImageView extends ImageView {

    private static final int INVALID_POINTER_ID = -1;

    private float mPosX;
    private float mPosY;

    private float mLastTouchX;
    private float mLastTouchY;
    private float mLastGestureX;
    private float mLastGestureY;
    private int mActivePointerId = INVALID_POINTER_ID;

    private ScaleGestureDetector mScaleDetector;
    private float mScaleFactor = 1.f;

    public MyImageView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
        mScaleDetector = new ScaleGestureDetector(getContext(), new ScaleListener());
    }

    public MyImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        // Let the ScaleGestureDetector inspect all events.
        mScaleDetector.onTouchEvent(ev);

        final int action = ev.getAction();
        switch (action & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN: {
                if (!mScaleDetector.isInProgress()) {
                    final float x = ev.getX();
                    final float y = ev.getY();

                    mLastTouchX = x;
                    mLastTouchY = y;
                    mActivePointerId = ev.getPointerId(0);
                }
                break;
            }
            case MotionEvent.ACTION_POINTER_1_DOWN: {
                if (mScaleDetector.isInProgress()) {
                    final float gx = mScaleDetector.getFocusX();
                    final float gy = mScaleDetector.getFocusY();
                    mLastGestureX = gx;
                    mLastGestureY = gy;
                }
                break;
            }
            case MotionEvent.ACTION_MOVE: {

                // Only move if the ScaleGestureDetector isn't processing a gesture.
                if (!mScaleDetector.isInProgress()) {
                    final int pointerIndex = ev.findPointerIndex(mActivePointerId);
                    final float x = ev.getX(pointerIndex);
                    final float y = ev.getY(pointerIndex);

                    final float dx = x - mLastTouchX;
                    final float dy = y - mLastTouchY;

                    mPosX += dx;
                    mPosY += dy;

                    invalidate();

                    mLastTouchX = x;
                    mLastTouchY = y;
                }
                else{
                    final float gx = mScaleDetector.getFocusX();
                    final float gy = mScaleDetector.getFocusY();

                    final float gdx = gx - mLastGestureX;
                    final float gdy = gy - mLastGestureY;

                    mPosX += gdx;
                    mPosY += gdy;

                    invalidate();

                    mLastGestureX = gx;
                    mLastGestureY = gy;
                }

                break;
            }
            case MotionEvent.ACTION_UP: {
                mActivePointerId = INVALID_POINTER_ID;
                break;
            }
            case MotionEvent.ACTION_CANCEL: {
                mActivePointerId = INVALID_POINTER_ID;
                break;
            }
            case MotionEvent.ACTION_POINTER_UP: {

                final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) 
                        >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
                final int pointerId = ev.getPointerId(pointerIndex);
                if (pointerId == mActivePointerId) {
                    // This was our active pointer going up. Choose a new
                    // active pointer and adjust accordingly.
                    final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
                    mLastTouchX = ev.getX(newPointerIndex);
                    mLastTouchY = ev.getY(newPointerIndex);
                    mActivePointerId = ev.getPointerId(newPointerIndex);
                }
                else{
                    final int tempPointerIndex = ev.findPointerIndex(mActivePointerId);
                    mLastTouchX = ev.getX(tempPointerIndex);
                    mLastTouchY = ev.getY(tempPointerIndex);
                }

                break;
            }
        }

        return true;
    }

    @Override
    public void onDraw(Canvas canvas) {

        canvas.save();

        canvas.translate(mPosX, mPosY);

        if (mScaleDetector.isInProgress()) {
            canvas.scale(mScaleFactor, mScaleFactor, mScaleDetector.getFocusX(), mScaleDetector.getFocusY());
        }
        else{
            canvas.scale(mScaleFactor, mScaleFactor, mLastGestureX, mLastGestureY);
        }
        super.onDraw(canvas);
        canvas.restore();
    }

    private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
        @Override
        public boolean onScale(ScaleGestureDetector detector) {
            mScaleFactor *= detector.getScaleFactor();

            // Don't let the object get too small or too large.
            mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 10.0f));

            invalidate();
            return true;
        }
    }
}

这篇关于缩放和平移ImageView的安卓的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆