2012-08-29 48 views
11

मैंने एक छवि दृश्य के लिए ज़ूम और पैन क्लास बनाया है।ज़ूम और पनिंग ImageView एंड्रॉइड

विशेषताएं मैं बनाने की कोशिश कर रहा हूं। - यह एक उंगली स्पर्श और आंदोलन पर निर्भर करता है - यह दो उंगली स्पर्श और आंदोलन पर ज़ूम करता है और पैन

अधिकांश भाग के लिए यह बहुत अच्छी तरह से काम करता है। जब मैं निम्नलिखित करता हूं तो इसमें थोड़ा सा बग होता है: - मैं एक उंगली के साथ घूमता हूं (स्थिति: कोई समस्या नहीं) - मैंने दूसरी उंगली, ज़ूम और पैन डाली (स्थिति: कोई समस्या नहीं) - मैंने अपना दूसरा रिलीज़ किया उंगली (स्थिति: छवि थोड़ी कूदती है)

उम्मीद कर रहा था कि कोई इसे हल करने में मेरी सहायता कर सकता है।

मैं सोच रहा हूँ यह किसी भी मदद में "मामले MotionEvent.ACTION_POINTER_UP"

mLastTouchX और mLastTouchY को रीसेट बहुत सराहना की जाएगी साथ क्या करना है चाहिए कि!

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; 
     } 
    } 
} 
+0

एचएम। अपना कोड आज़माया और छोटी छवि के साथ देखा कि फिर मैंने दूसरी उंगली को छवि 'कूद' दिया। क्या यह बग आप रेफर कर रहे हैं? – sandrstar

+0

हां, कूद वह है जो मैं हल करने की कोशिश कर रहा हूं। – Hank

+0

ऐसा लगता है कि यह फोकस निर्देशांक के उपयोग के कारण होता है। आज कोड को डीबग करने का प्रयास करेंगे। – sandrstar

उत्तर

16

लगता canvas.scale() 'OnDraw' विधि के 'शेष' बयान में आवश्यक mLastGestureX और mLastGestureY कूद को रोकने के लिए। मैं भी mLastTouchX और mLastTouchY ताज़ा जब वापस एक उंगली करने के लिए पैन के लिए जा रहा 'मामले MotionEvent.ACTION_POINTER_UP'

यहाँ अंतिम, हर कोई यह अतीत छवि सीमा पैनिंग को सीमित नहीं करता का कारण बनता है लेकिन यह है कि पूरा करने के लिए आसान होना चाहिए के अनुरूप नहीं हो सकता है , उस विषय पर वहां बहुत सारी चर्चाएं हैं।

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; 
     } 
    } 
} 
+0

इसे ImageView से बाहर जाने से कैसे प्रतिबंधित करें? –

+0

ओपनजीएल में सबकुछ हटा दिया क्योंकि यह एक मजबूत ग्राफिकल मैपर था, लेकिन मुझे लगता है कि अगर आप अपनी छवि की सीमाओं को कभी भी ज़ूम केवेल पर देखते हैं, तो आप शायद – Hank

+0

पर पैनिंग को रोक सकते हैं और रोक सकते हैं यह दूसरी उंगली होने पर भी कूदता है स्क्रीन पर रखा गया। –

1

मैं एक सप्ताह से अधिक समय तक इस समस्या के समाधान के साथ टकरा रहा हूं, और यह मुझे समस्याओं का एक टन दे रहा है। हालांकि, मैंने इस मुद्दे को काफी कम कर दिया है। ऊपर आपका समाधान मेरे लिए काम नहीं करता है, लेकिन नीचे मेरा समाधान करीब है। मुद्दा यह है कि जब भी दूसरी उंगली दबाया जाता है या उठाया जाता है तो यह कूदता है। मैंने पाया है कि ऐसा इसलिए होता है क्योंकि एमपीओएसएक्स और एमपीओसी हमेशा सच नहीं होते हैं कि वेरिएबल का प्रतिनिधित्व करने के लिए क्या हैं। यहाँ मैं क्या मतलब है:

ACTION_MOVE कहा जाता है और कोड "और" बयान (ज़ूम घटनाओं से निपटने के लिए) फोकस में परिवर्तन के अनुसार, mPosX और mPosY केवल बदल रहे हैं, नहींमें प्रवेश करती है ज़ूम में बदलें। इसका मतलब है कि दो अंगुलियों के साथ काम करना, और दो अंगुलियों के साथ ज़ूम करना काम करता है, लेकिन बदलते ज़ूम के संबंध में एमपीओएसएक्स और एमपीसीई उचित रूप से बदल नहीं रहे हैं।

मैं ज़ूम (mScaleDetector.getScaleFactor()) में अंतर परिवर्तनों और फोकस में अंतर परिवर्तनों का उपयोग करके इसे ठीक करने के तरीकों को समझने का प्रयास कर रहा हूं, लेकिन मैं तर्क के माध्यम से पर्याप्त रूप से काम नहीं कर सकता कुछ काम करता है जो काम करता है।

एक और समाधान सभी ज़ूम ऑपरेशंस को ऑन टचलिस्टर में स्थानांतरित करना है, और पूरी तरह से स्केललिस्टर से छुटकारा पा रहा है। इसका मतलब बहुत अधिक गणित है, लेकिन यह निश्चित रूप से एक समाधान होगा।

यहाँ OnDraw है:

@Override 
    public void onDraw(Canvas c) { 
     c.save(); 

     if (mScaleDetector.isInProgress()) { 
      c.scale(mScaleFactor, mScaleFactor, mLastGestureX - mPosX, 
        mLastGestureY - mPosY); 
     } else { 
      c.scale(mScaleFactor, mScaleFactor, mLastGestureX, mLastGestureY); 
     } 

     c.translate(mPosX/mScaleFactor, mPosY/mScaleFactor); 

     // drawing instruction here 

     c.restore(); 
    } 

यहाँ कैसे कोड उंगली प्रेस के प्रति प्रतिक्रिया करता है:

@Override 
    public boolean onTouchEvent(MotionEvent ev) { 
     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_DOWN: { 
      if (!mScaleDetector.isInProgress()) { 
       final float gx = mScaleDetector.getFocusX(); 
       final float gy = mScaleDetector.getFocusY(); 

       mLastGestureX = gx; 
       mLastGestureY = gy; 
      } 
      break; 
     } 

     case MotionEvent.ACTION_MOVE: { 
      if (!mScaleDetector.isInProgress()) { 
       Log.i("hi", "SD not in progress"); 
       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 { 
       Log.i("hi", "SD in progress"); 
       final float gx = mScaleDetector.getFocusX(); 
       final float gy = mScaleDetector.getFocusY(); 

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

       mPosX += gdx; 
       mPosY += gdy; 

       // SOMETHING NEEDS TO HAPPEN RIGHT HERE. 

       invalidate(); 

       mLastGestureX = gx; 
       mLastGestureY = gy; 
      } 

      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; 
    } 

और हालांकि यह ज्यादातर संबंधित न हो, यहाँ ScaleListener है:

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

      invalidate(); 
      return true; 
     } 
    } 

फिर , यह कोड पूरी तरह से काम नहीं कर रहा है, लेकिन यह बहुत करीब है। मैंने ऊपर दिए गए सटीक मुद्दे को समझाया है और अभी भी इसे काम करने में परेशानी है। मुझे नहीं पता कि यह आपकी अधिसूचनाओं में पॉप अप करेगा, लेकिन उम्मीद है कि कोई इसे देखेगा और मेरी मदद करेगा।

+0

धन्यवाद, यह पिछले कोड में सुधार है, लेकिन यह तब भी कूदता है जब स्क्रीन पर दूसरी उंगली छूती है। –

0

हैंक का समाधान मेरे लिए काम करता है। मैंने एक रीसेट फ़ंक्शन जोड़ा ताकि बाद की छवियों को सामान्य रूप से प्रदर्शित किया जा सके।

public void ResetView() { 
     mScaleFactor = 1.f; 
     mPosX = 0.f; 
     mPosY = 0.f; 
    } 
0

डब्ल्यू/ओ कोड को देखकर मुझे लगता है कि आप 2 उंगलियों पर 2 अंगुलियों के आधार पर स्थिति गणना कर रहे हैं। आप हमेशा उस मामले में कूद लेंगे।

+1

लॉल समस्या हल होने के तीन साल बाद आप उत्तर क्यों देंगे? – Hank

+2

लॉल आपको क्यों परवाह है? –

 संबंधित मुद्दे

  • कोई संबंधित समस्या नहीं^_^