2012-07-05 19 views
7

मैं आठ घंटे तक इस समस्या पर फंस गया हूं, इसलिए मुझे लगा कि यह कुछ मदद पाने का समय था।कैनवास पिंच-ज़ूम इन पॉइंट्स इन पॉइंट्स

मेरी समस्या शुरू करने से पहले, मैं बस यह जानूंगा कि मैं इस साइट और Google के माध्यम से रहा हूं, और मुझे जो भी जवाब मिले हैं, उनमें से कोई भी मदद नहीं मिली है। (This एक, another, और another है।)

यहाँ सौदा है: मैं एक वर्ग कि SurfaceView फैली है और यह कई तरीकों को ओवरराइड करता है (यह MySurface कॉल)। आम तौर पर, यह कई वर्गों और पाठ बक्से खींचता है, जो ठीक है। जैसे ही उपयोगकर्ता स्पर्श करना शुरू कर देता है, यह Bitmap में परिवर्तित हो जाता है, फिर प्रत्येक फ्रेम को तब तक खींचता है जब तक कि उपयोगकर्ता रिलीज़ न हो जाए।

यहां रगड़ है: मैं ऐसी कार्यक्षमता को कार्यान्वित करना चाहता हूं कि उपयोगकर्ता स्क्रीन पर दो अंगुलियों को रख सकता है, ज़ूम करने के लिए चुटकी लगा सकता है, और चारों ओर पैन भी कर सकता है (लेकिन केवल दो उंगलियों के साथ)।

मैं पिंच-टू-जूम के कुछ कार्यान्वयन पाया जाता है और निम्नलिखित के माध्यम से MySurface में मेरी Canvas वस्तु के लिए उन्हें अनुकूलित:

public void onDraw(Canvas canvas) { 
    super.onDraw(canvas); 

    canvas.save(); 

    canvas.scale(mScaleVector.z, mScaleVector.z); // This is the scale factor as seen below 
    canvas.translate(mScaleVector.x, mScaleVector.y); // These are offset values from 0,0, both working fine 

    // Start draw code 

    // ... 

    // End draw code 

    canvas.restore(); 
} 
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener { 
    @Override 
    public boolean onScale(ScaleGestureDetector detector) { 
     float factor = detector.getScaleFactor(); 
     if (Math.abs(factor - 1.0f) >= 0.0075f) { 
      mScaleVector.z *= factor; 
      mScaleVector.z = Math.max(MIN_ZOOM, Math.min(mScaleVector.z, MAX_ZOOM)); 
     } 

     // ... 

     invalidate(); 

     return true; 
    } 
} 
public boolean onTouchEvent(MotionEvent event) { 
    int action = event.getAction() & MotionEvent.ACTION_MASK; 
    int pointerIndex = (event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; 
    if (event.getPointerCount() == 2) { 
     if (action == MotionEvent.ACTION_POINTER_DOWN && pointerIndex == 1) { 
      // The various pivot coordinate codes would belong here 
     } 
    } 

    detector.onTouchEvent(event); // Calls the Scale Gesture Detector 
    return true; 
} 

दोनों तत्वों अच्छा काम है - आगे और पीछे और चुटकी स्क्रॉल -ट-ज़ूम - एक बड़ी समस्या है। चुटकी-टू-ज़ूम, जब उपयोग किया जाता है, तो उंगली बिंदु में ज़ूम करने के बजाय, 0,0 बिंदु पर ज़ूम करता है।

मैं तरीके इसे ठीक करने का एक बहुत कोशिश की है:

  • canvas.scale(mScaleVector.z, mScaleVector.z, mScaleVector.x, mScaleVector.y); का उपयोग करना; जाहिर है, यह अवांछित परिणाम उत्पन्न करता है क्योंकि mScaleVector x और y मान 0-ऑफसेट हैं।
  • एक "पिवट" समन्वय का प्रबंधन करना जो translate() विधि के समान ऑफ़सेट का उपयोग करता है, लेकिन यह या तो 0,0 समस्या उत्पन्न करता है, या दृश्य स्पर्श होने पर चारों ओर कूदता है।
  • कई अन्य चीजें ... मैंने उपर्युक्त पिवट समन्वय के साथ बहुत कुछ किया है, उपयोगकर्ता के पहले स्पर्श पर अपना स्थान आधार बनाने की कोशिश कर रहा है, और इसे प्रत्येक लगातार संकेत के स्पर्श के सापेक्ष ले जा रहा है।

इसके अतिरिक्त, यह कैनवास बाध्य होना चाहिए, इसलिए उपयोगकर्ता हमेशा के लिए स्क्रॉल नहीं कर सकता है। हालांकि, जब मैं .scale(sx, sy, px, py) विधि का उपयोग करता हूं, तो यह .translate() में सेट की गई किसी भी सीमा से परे चीजों को धक्का देता है।

मैं ... इस बिंदु पर कुछ भी ज्यादा खुला हूं। मुझे पता है कि इस कार्यक्षमता को जोड़ा जा सकता है, क्योंकि यह एंड्रॉइड 4.0 गैलरी में देखा जाता है (जब एक छवि को देखते हैं)। मैंने स्रोत कोड को ट्रैक करने का प्रयास किया है जो इसका प्रबंधन नहीं करता है।

+0

मैं व्यक्तिगत रूप से 'ऑन टचवेन्ट' का उपयोग करके दो अंगुली की स्थिति को संभालता हूं। इसके साथ, आप आसानी से मध्य बिंदु पा सकते हैं, और स्केलिंग की कितनी आवश्यकता है। – Doomsknight

+0

यदि आप इस समस्या को हल कर चुके हैं तो मुझे समाधान पोस्ट कर सकते हैं, मुझे एक ही समस्या का सामना करना पड़ रहा है, और मेरा ग्राहक है .... :(, या आप मुझे बता सकते हैं कि आपने समस्या को कैसे हल किया है। धन्यवाद – AkashG

उत्तर

13

यहां कोड है जिसका उपयोग मैं का उपयोग कर ImageView में चुटकी ज़ूम को लागू करने के लिए करता हूं। कम या कोई संशोधन के साथ आप इसका भी उपयोग करने में सक्षम होना चाहिए, क्योंकि आप Canvas पर आकर्षित करने के लिए भी रूपांतरण मार्श का उपयोग कर सकते हैं।

@Override 
public boolean onScale(ScaleGestureDetector detector) { 
    float mScaleFactor = (float) Math.min(
     Math.max(.8f, detector.getScaleFactor()), 1.2); 
    float origScale = saveScale; 
    saveScale *= mScaleFactor; 
    if (saveScale > maxScale) { 
     saveScale = maxScale; 
     mScaleFactor = maxScale/origScale; 
    } else if (saveScale < minScale) { 
     saveScale = minScale; 
     mScaleFactor = minScale/origScale; 
    } 
    right = width * saveScale - width 
      - (2 * redundantXSpace * saveScale); 
    bottom = height * saveScale - height 
      - (2 * redundantYSpace * saveScale); 
    if (origWidth * saveScale <= width 
      || origHeight * saveScale <= height) { 
     matrix.postScale(mScaleFactor, mScaleFactor, width/2, height/2); 
     if (mScaleFactor < 1) { 
      matrix.getValues(m); 
      float x = m[Matrix.MTRANS_X]; 
      float y = m[Matrix.MTRANS_Y]; 
      if (mScaleFactor < 1) { 
       if (Math.round(origWidth * saveScale) < width) { 
        if (y < -bottom) 
         matrix.postTranslate(0, -(y + bottom)); 
        else if (y > 0) 
         matrix.postTranslate(0, -y); 
       } else { 
        if (x < -right) 
         matrix.postTranslate(-(x + right), 0); 
        else if (x > 0) 
         matrix.postTranslate(-x, 0); 
       } 
      } 
     } 
    } else { 
     matrix.postScale(mScaleFactor, mScaleFactor, detector.getFocusX(), detector.getFocusY()); 
     matrix.getValues(m); 
     float x = m[Matrix.MTRANS_X]; 
     float y = m[Matrix.MTRANS_Y]; 
     if (mScaleFactor < 1) { 
      if (x < -right) 
       matrix.postTranslate(-(x + right), 0); 
      else if (x > 0) 
       matrix.postTranslate(-x, 0); 
      if (y < -bottom) 
       matrix.postTranslate(0, -(y + bottom)); 
      else if (y > 0) 
       matrix.postTranslate(0, -y); 
     } 
    } 
    return true; 
} 

मेरे मामले में, मैं दृश्य के onMeasure() विधि में आवश्यक मानों का परिकलन किया, आप अपने SurfaceView

width = MeasureSpec.getSize(widthMeasureSpec); // Change this according to your screen size 
height = MeasureSpec.getSize(heightMeasureSpec); // Change this according to your screen size 

// Fit to screen. 
float scale; 
float scaleX = (float) width/(float) bmWidth; 
float scaleY = (float) height/(float) bmHeight; 
scale = Math.min(scaleX, scaleY); 
matrix.setScale(scale, scale); 
setImageMatrix(matrix); 
saveScale = 1f; 
scaleMappingRatio = saveScale/scale; 

// Center the image 
redundantYSpace = (float) height - (scale * (float) bmHeight); 
redundantXSpace = (float) width - (scale * (float) bmWidth); 
redundantYSpace /= (float) 2; 
redundantXSpace /= (float) 2; 

matrix.postTranslate(redundantXSpace, redundantYSpace); 

origWidth = width - 2 * redundantXSpace; 
origHeight = height - 2 * redundantYSpace; 
right = width * saveScale - width - (2 * redundantXSpace * saveScale); 
bottom = height * saveScale - height - (2 * redundantYSpace * saveScale); 
setImageMatrix(matrix); 

एक छोटी सी स्पष्टीकरण में और इस कहीं आप ऐसा करना चाहेंगे:

saveScaleBitmap

mScaleFactor का वर्तमान पैमाने अनुपात है ई कारक आपको अपने पैमाने अनुपात को गुणा करना है।

maxScale और minScale निरंतर मूल्य हो सकते हैं।

width और height स्क्रीन के आयाम हैं।

redundantXSpace और redundantYSpace छवि सीमाओं और स्क्रीन सीमाओं के बीच खाली के बाद से छवि केंद्रित है जब में यह छोटे स्क्रीन तो है

origHeight और origWidth बिटमैप के आकार

matrix है कर रहे हैं बिटमैप

चाल यह है कि जब मैंने पहली बार शुरूआत पर छवि को स्केल किया और केंद्रित किया, तो मैंने स्केल अनुपात 1 औरके साथ चुनामैंने उससे संबंधित छवि के वास्तविक पैमाने मानों को मैप किया।

+2

ओह मैन, समीक्षा के बाद और आपके कोड के पहलुओं का पूरी तरह से परीक्षण करते हुए, मैंने पाया कि उन मैट्रिक्स ट्रांसफॉर्मेशन कुंजी थे! अगर मैं कर सकता तो मैं आपको एक बियर खरीदूंगा! ए +, अच्छा सर। – Eric

+1

आपका स्वागत है, मैंने सही तरीके से पता लगाने में बहुत समय बिताया , जब मैंने ऊपर दिए गए कोड को लिखना शुरू किया, तो मैंने सोचा कि यह साझा करने लायक होगा। –

+0

@ AdamL.Mónos महान काम एडम, चीयर्स! –

-1
protected override void OnDraw(Canvas canvas) 
    { 
     canvas.Save(); 

     int x = (int)(canvas.Width * mScaleFactor - canvas.Width)/2; 
     int y = (int)(canvas.Height * mScaleFactor - canvas.Height)/2; 

     if (mPosX > (canvas.Width + x - 50)) 
     { 
      mPosX = canvas.Width + x - 50; 
     } 
     if (mPosX < (50 - canvas.Width - x)) 
     { 
      mPosX = 50 - canvas.Width - x; 
     } 
     if (mPosY > (canvas.Height + y - 50)) 
     { 
      mPosY = canvas.Height + y - 50; 
     } 
     if (mPosY < (50 - canvas.Height - y)) 
     { 
      mPosY = 50 - canvas.Height - y; 
     } 

     canvas.Translate(mPosX, mPosY); 
     canvas.Scale(mScaleFactor, mScaleFactor, canvas.Width/2, canvas.Height/2); 
     base.OnDraw(canvas); 
     canvas.Restore(); 
    } 

यह मोनोड्रॉइड कोड है, लेकिन इसे आसानी से जावा में परिवर्तित किया जा सकता है। आप अपनी बाध्यता के लिए जो भी मूल्य चुन सकते हैं (यहां 50 पिक्सल मार्जिन है)

+0

यहां एक लाइब्रेरी है जो यह करेगी। https://stackoverflow.com/questions/6578320/कैसे करने वाली लागू ज़ूम-खींचें और रोटेशन करने वाली एक छवि में एंड्रॉयड/47861501 # 47861501 – user2288580

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