【问题标题】:Image in Canvas with touch events带有触摸事件的 Canvas 中的图像
【发布时间】:2011-08-10 05:49:41
【问题描述】:

看起来很简单,但我在实现方面遇到了问题。

我想要一个在屏幕上显示图像的画布,包括onTouch 事件。 我试过ImageView 但我无法使用画布。 我已经尝试过SurfaceView,并且能够在屏幕上的画布中显示图像,但是我在处理 onTouch 事件(缩放、平移)时遇到了问题。

我需要画布,因为我将在我的代码中渲染图像。

有人可以告诉我这样做的正确方法吗?

【问题讨论】:

    标签: android image android-canvas ontouchlistener


    【解决方案1】:

    你可以用这个:

    import android.content.Context;
    import android.graphics.Canvas;
    import android.graphics.drawable.BitmapDrawable;
    import android.util.AttributeSet;
    import android.util.Log;
    import android.view.MotionEvent;
    import android.view.ScaleGestureDetector;
    import android.view.View;
    
    public class MyImageView extends View {
    
    private static final int INVALID_POINTER_ID = -1;
    
        private Drawable mImage;
        private float mPosX;
        private float mPosY;
    
        private float mLastTouchX;
        private float mLastTouchY;
        private int mActivePointerId = INVALID_POINTER_ID;
    
        private ScaleGestureDetector mScaleDetector;
        private float mScaleFactor = 1.f;
    
        public MyImageView(Context context) {
            this(context, null, 0);
        mImage = getResources().getDrawable(R.drawable.imagename);
    
            mImage.setBounds(0, 0, mImage.getIntrinsicWidth(), mImage.getIntrinsicHeight());
        }
    
        public MyImageView(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        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: {
                final float x = ev.getX();
                final float y = ev.getY();
    
                mLastTouchX = x;
                mLastTouchY = y;
                mActivePointerId = ev.getPointerId(0);
                break;
            }
    
            case MotionEvent.ACTION_MOVE: {
                final int pointerIndex = ev.findPointerIndex(mActivePointerId);
                final float x = ev.getX(pointerIndex);
                final float y = ev.getY(pointerIndex);
    
                // Only move if the ScaleGestureDetector isn't processing a gesture.
                if (!mScaleDetector.isInProgress()) {
                    final float dx = x - mLastTouchX;
                    final float dy = y - mLastTouchY;
    
                    mPosX += dx;
                    mPosY += dy;
    
                    invalidate();
                }
    
                mLastTouchX = x;
                mLastTouchY = y;
    
                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);
                }
                break;
            }
            }
    
            return true;
        }
    
        @Override
        public void onDraw(Canvas canvas) {
            super.onDraw(canvas);
    
            canvas.save();
            Log.d("DEBUG", "X: "+mPosX+" Y: "+mPosY);
            canvas.translate(mPosX, mPosY);
            canvas.scale(mScaleFactor, mScaleFactor);
            mImage.draw(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;
            }
        }
    
    }
    

    【讨论】:

    • 您能否指出如何在我的活动中使用此自定义视图?我已经使用这个自定义视图创建了布局,并且在我的活动中我有 setContentView(R.layouts.myImageLayout) ...猜这还不够吗?
    • 调用这个 setContentView(new MyImageView(this));并注意我已经从 MyImageView 的构造函数中删除了 1 个参数
    • 我已经尝试在我的活动中创建此类的实例,但是在绘制命中时我得到空白屏幕(没有显示图像) PS:构造函数 MyImageView(MapActivity) 未定义?
    • 哦,我发表评论时代码没有刷新……让我现在试试
    • 现在可以工作了...非常感谢您帮助我 hotveryspicy!万事如意!
    猜你喜欢
    • 2015-01-29
    • 1970-01-01
    • 2013-01-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多