2011-07-21 45 views
8

Özel bir SurfaceView uzatıyorum ve çimdik yakınlaştırma ve kaydırma yeteneğine sahip olmaya çalışıyorum. Tuvalimin çeviri matrisine sınırları nasıl yerleştirebilirim?

Ben kaydırma nasıl

@Override 
    public boolean onScroll(MotionEvent e1, MotionEvent e2, 
      float distanceX, float distanceY) { 

     // subtract scrolled amount 
     matrix.postTranslate(-distanceX, -distanceY); 

     rebound(); 

     invalidate(); 

     // handled 
     return true; 
    } 

Ben Büyütmek Nasıl:

@Override 
    public boolean onScale(ScaleGestureDetector detector) { 
     if (detector.isInProgress()) { 
      // get scale 
      float factor = detector.getScaleFactor(); 

      // Don't let the object get too small or too large. 
      if (factor * scale > 1f) { 
       factor = 1f/scale; 
      } else if (factor * scale < minScale) { 
       factor = minScale/scale; 
      } 

      // store local scale 
      scale *= factor; 

      // do the scale 
      matrix.preScale(factor, factor, detector.getFocusX(), detector.getFocusY()); 

      rebound(); 

      invalidate(); 
     } 

     return true; 
    } 

(referans için ben bu yöntemlerin her ikisi de anda onDraw :)

@Override 
protected void onDraw(Canvas canvas) { 
    super.onDraw(canvas); 

    canvas.save(); 
    canvas.setMatrix(matrix); 
    // [...] stuff drawn with matrix settings 
    canvas.restore(); 
    // [...] stuff drawn without matrix settings, as an overlay 
} 

için bu kodu kullanın iyi çalışıyor. Yakınlaştırma, minimum (0f ve 1f arası) ve maksimum (şu anda her zaman 1f) ölçek değeri doğru bir şekilde durdurulur. kullanılan

Küresel alanları:

  • drawW, drawH = float, geniş ölçekte tuval veri piksel boyutu = 1
  • parentW, = floatparentH, görünür bakış piksel boyutu .
  • matrix = android.graphics.Matrix.

sorun "rebound()" dir (belki daha iyi bir isme ihtiyacı var, heh) O otomatik görünümünde kalmak içeriğini zorlayacaktır uygulamak çalışılıyor yöntemi.

Sınırların nerede olması gerektiğini hesaplamak için çeşitli yöntemler denedim (dikdörtgenin içinde (0, 0, parentW, parentH)) ve çok uzağa gittiğinde matrisi "geri" çevirin.

Şu anda sahip olduğum, kesinlikle işe yaramıyor, bunun yerine sağa doğru çok daha fazla itmek. Problemin benim matematik olduğumu hissediyorum, fikrim değil. Birisi, matrisini çok uzağa çeviren ve/veya bu uygulamadaki denememle sorunları çözen daha basit veya daha temiz kodlar bulabilir mi? o üst görünmesi için kullanılan çekler

public void rebound() { 
    // bounds 
    RectF currentBounds = new RectF(0, 0, drawW, drawH); 
    matrix.mapRect(currentBounds); 
    RectF parentBounds = new RectF(0, 0, parentW, parentH/2); 

    PointF diff = new PointF(0, 0); 

    if (currentBounds.left > parentBounds.left) { 
     diff.x += (parentBounds.left - currentBounds.left); 
    } 
    if (currentBounds.top > parentBounds.top) { 
     diff.y += (parentBounds.top - currentBounds.top); 
    } 
    if (currentBounds.width() > parentBounds.width()) { 
     if (currentBounds.right < parentBounds.right) { 
      diff.x += (parentBounds.right - currentBounds.right); 
     } 
     if (currentBounds.bottom < parentBounds.bottom) { 
      diff.y += (parentBounds.bottom - currentBounds.bottom); 
     } 
    } 

    matrix.postTranslate(diff.x, diff.y); 
} 

matris bir alan oldu önce yazdığım bir önceki sürümü bırakılırsa çalıştı (Sadece canvas.scale()onDraw sonra canvas.translate() kullanılır):

public void rebound() { 
    // bounds 
    int boundTop = 0; 
    int boundLeft = 0; 
    int boundRight = (int)(-scale * drawW + parentW); 
    int boundBottom = (int)(-scale * drawH + parentH); 

    if (boundLeft >= boundRight) { 
     mScrollX = Math.min(boundLeft, Math.max(boundRight, mScrollX)); 
    } else { 
     mScrollX = 0; 
    } 
    if (boundTop >= boundBottom) { 
     mScrollY = Math.min(boundTop, Math.max(boundBottom, mScrollY)); 
    } else { 
     mScrollY = 0; 
    } 
} 

Yeni yolu kullanıyorum, böylece detector.getFocusX(), detector.getFocusY() merkezini doğru şekilde ölçeklendirebiliyorum.

UPDATE: Yöntemi şu an için değiştirdim. Sadece biraz çalışır, hala y yönünü merkezden sınırlar ve zum seviyesini değiştirdikten sonra yanlıştır. Ayrıca "preScale" ve "postTranslate" yaptım, böylece (anladığım kadarıyla), her zaman ölçeği uyguladıktan sonra tercüme etmeli ve onları karıştırmamalı.

FINAL UPDATE: Şimdi çalışıyor.Ben geri sınırları onu çevirerek istemediğiniz herhangi kaydırma olumsuzlar

public void rebound() { 
    // make a rectangle representing what our current canvas looks like 
    RectF currentBounds = new RectF(0, 0, drawW, drawH); 
    matrix.mapRect(currentBounds); 
    // make a rectangle representing the scroll bounds 
    RectF areaBounds = new RectF((float) getLeft(), 
            (float) getTop(), 
            (float) parentW + (float) getLeft(), 
            (float) parentH + (float) getTop()); 

    // the difference between the current rectangle and the rectangle we want 
    PointF diff = new PointF(0f, 0f); 

    // x-direction 
    if (currentBounds.width() > areaBounds.width()) { 
     // allow scrolling only if the amount of content is too wide at this scale 
     if (currentBounds.left > areaBounds.left) { 
      // stop from scrolling too far left 
      diff.x = (areaBounds.left - currentBounds.left); 
     } 
     if (currentBounds.right < areaBounds.right) { 
      // stop from scrolling too far right 
      diff.x = (areaBounds.right - currentBounds.right); 
     } 
    } else { 
     // negate any scrolling 
     diff.x = (areaBounds.left - currentBounds.left); 
    } 

    // y-direction 
    if (currentBounds.height() > areaBounds.height()) { 
     // allow scrolling only if the amount of content is too tall at this scale 
     if (currentBounds.top > areaBounds.top) { 
      // stop from scrolling too far above 
      diff.y = (areaBounds.top - currentBounds.top); 
     } 
     if (currentBounds.bottom < areaBounds.bottom) { 
      // stop from scrolling too far below 
      diff.y = (areaBounds.bottom - currentBounds.bottom); 
     } 
    } else { 
     // negate any scrolling 
     diff.y = (areaBounds.top - currentBounds.top); 
    } 

    // translate 
    matrix.postTranslate(diff.x, diff.y); 
} 

: Burada yorumlarla bir çalışma rebound yöntemidir. İçerik çok küçükse, içeriği sol üstte olacak şekilde zorluyorsa kaydırma işlemini tamamen iptal eder.

cevap

0

Tam olarak yakınlaştırmak için kendi tutamımı açmak için böyle bir şey uyguladım. Problemi y ekseninizin kapalı olduğundan şüpheliyim, tam ekran boyutunun olmaması için görüşe inebilir veya koordinatlarla eşleşmek için koordinatları değiştirmeyebilirsiniz.

Uygulamam bir ölçek faktörü hesaplar, uygular: canvas.scale (pinchZoomScale, pinchZoomScale); Daha sonra, ekranın fiziksel boyutunu piksel olarak hesaplar, metrelere dönüştürür ve son olarak ölçekleme faktörünü uygulayarak tüm çizilen nesnelerin doğru bir şekilde ofsetini sağlar.

Bu uygulama, her zaman ekranın merkezinde ne olması gerektiğini bilmenizi ve yakınlaştırma seviyesi ne olursa olsun ona kilitlenmeyi temel alır.

+0

Haklısınız! Görünüm tüm ekran boyutu değil. Tuvalin görünümü yerine matris dönüşümleri ekrana göre mi? Tabanın tuvaline değil, tuvalete göre en mantıklı olacağını varsayıyordum ... – Ribose

+0

Matris, tuval ile göreceli, ama 0,0 konumunda sabitleniyor, böylece ölçeği iki katına çıkararak 5,5'e çekecek. 2.5.2.5 'da görünmesini sağladım Bazı durumlarda görünüm boyutunun karışık olabileceğini ve ekran boyutunu kullanacağınız gerçek görünümü değil bir kılavuz olarak kullanmayı denedim. Tuval üzerindeki nesnelerin pozisyonu için ölçeklememle birlikte tuvalin güzel oynaması için ölçeklememi almak çok fazla deneme ve hata aldı. – ScouseChris

+1

Teşekkür ederiz! Bir sürü deneme-yanılma ile sonunda işe yaradım. – Ribose

İlgili konular