2012-05-02 20 views
5

İçeriğinin kaydırılmasını ve yakınlaştırılmasını destekleyen bir ViewGroup oluşturmaya çalışıyorum. İnternette bulabildiğim tek şey, bir ImageView'da bunu yapmak için bir fikir ve uygulama oldu, ama asla bir konteyner. Bir haritayı görüntülemek istiyorum ve bunun üzerine ImageButtons olan çoklu işaretleyicileri görüntülemek istiyorum, böylece kullanıcı daha fazla bilgi almak için onlara dokunabilir. Bu, iOS'ta UIScrollView aracılığıyla elde edildi, ancak Android'de bir alternatif bulamadım.Yakınlaştırılabilir/kaydırılabilir bir kapsayıcı oluşturma

Bir FrameView kullanmaya karar verdim, böylece bir ImageView'i arka plan olarak görüntüye ayarlayabiliyordum ve üstüne ImageButtons'u ekleyebileceğim ve kenar boşluklarını kullanarak yerleştirebileceğim bir RelativeLayout ekleyebiliyorum.

TouchImageView here'un uygulanmasının bir kısmını ödünç aldım, ancak karmaşıklıklara girdim. Panning ile başladım ve kısmen başarılı oldum, konteynırı kaplıyor, ama panning iğrenç bir şekilde çalışıyor, çok fazla titriyor. İşte kodum:

public class ScrollingViewGroup extends FrameLayout { 

    private int x = 0; 
    private int y = 0; 

    // We can be in one of these 3 states 
    static final int NONE = 0; 
    static final int DRAG = 1; 
    static final int ZOOM = 2; 
    int mode = NONE; 

    // Remember some things for zooming 
    PointF last = new PointF(); 
    PointF start = new PointF(); 

public ScrollingViewGroup(Context context) { 
     super(context); 
     sharedConstructing(context); 
    } 

    public ScrollingViewGroup(Context context, AttributeSet attrs) { 
     super(context, attrs); 
     sharedConstructing(context); 
    } 

    private void sharedConstructing(Context context) { 
     super.setClickable(true); 
     this.context = context; 
     mScaleDetector = new ScaleGestureDetector(context, new ScaleListener()); 

    setOnTouchListener(new OnTouchListener() { 

      @Override 
      public boolean onTouch(View v, MotionEvent event) { 
       mScaleDetector.onTouchEvent(event); 

       PointF curr = new PointF(event.getX(), event.getY()); 

       switch (event.getAction()) { 
       case MotionEvent.ACTION_DOWN: 
        last.set(event.getX(), event.getY()); 
        start.set(last); 
        mode = DRAG; 
        break; 
       case MotionEvent.ACTION_MOVE: 
        if (mode == DRAG) { 
         float deltaX = curr.x - last.x; 
         float deltaY = curr.y - last.y; 
         Log.d("ScrollingViewGroup", Float.toString(deltaX)); 
         Log.d("ScrollingViewGroup", Float.toString(deltaY)); 
         float scaleWidth = Math.round(origWidth * saveScale); 
         float scaleHeight = Math.round(origHeight * saveScale); 


         x += deltaX; 
         y += deltaY; 



         last.set(curr.x, curr.y); 

        } 
        break; 

       case MotionEvent.ACTION_UP: 
        mode = NONE; 
        int xDiff = (int) Math.abs(curr.x - start.x); 
        int yDiff = (int) Math.abs(curr.y - start.y); 
        if (xDiff < CLICK && yDiff < CLICK) 
         performClick(); 
        break; 

       case MotionEvent.ACTION_POINTER_UP: 
        mode = NONE; 
        break; 
       } 
       // setImageMatrix(matrix); 
       setTranslationX(x); 
       setTranslationY(y); 
       invalidate(); 
       return true; // indicate event was handled 
      } 

     }); 
    } 

Herhangi bir fikir çok takdir edilmektedir.

düzenleme: jitter neden gibi görünüyor, çünkü hareket ederken, deltaX ve deltaY pozitif ve negatif sayılar arasında değişiyor, LogCat kontrol ediliyor ... hala neden emin değilim. Bu, her seferinde farklı değerler veren curr değişkeninden kaynaklanır, ancak tutarlı olmak yerine, parmak ileriye değil, ileri geri hareket ediyormuş gibi görünürler. Örneğin, curr.x yerine, 0,1,2,3,4, vb., 0,1,0,5,2,1,5, vb. Olduğundan emin değilim.

+0

Buna bir çözüm buldunuz mu? Ben de aynı şeyi arıyorum. – 0xSina

+0

düğmeli bir yakınlaştırma/kaydırma yapabilen harita Hey, özür dilerim, bir süre önce şirketten ayrıldım ve kod sağlayamadım, bazı geçici çözümler buldum, ancak bunu nasıl yaptığımı hatırlayamıyorum. –

cevap

0

bazı önkoşullar ile çalışan bir çözüm var: kapta

  • ürün tipi ImageView olması gerekiyor
  • Bütün resimler eşit Büyütmek için aynı boyutta olması gerekir

Kaptaki öğeler yakınlaştırılabilir ve çevrilebilir (ancak aynı anda değil). Kod, bir kullanıcının hareket etmek veya yakınlaştırma yapmak yerine tıklatılıp tıklanmadığını da belirleyebilir. ImageView'lar bir FrameLayout'ta bir ArrayList'te saklanır ve ölçeklenir ve birlikte taşınır. Bu kodun bazı bölümleri, gerçekten iyi bir Android kitabı olan "Hello, Android" dan alınan Ed Burnette (Link) tarafından ZDNet üzerindeki çok güzel bir makaleden alınmıştır.

Bu kodu okuyun. Bu sınıfı, herhangi bir etkinlikte düzen olarak kullanabilirsiniz. XML'de bile kullanabilmeniz gerekir. Şimdilik, düzen oluşturulduğunda yüklenecek olan resim görüntülerini kodlayabileceğiniz kurucuda çağrılan initializeViews() yöntemi vardır. "ArrayList sampleBitmaps = new ArrayList();" satırından sonra bu yönteme bazı bit eşlemler eklemelisiniz. Gerçek kullanım için, görünümleri dinamik olarak ekleyebileceğiniz addImageView (ImageView öğesi) yöntemini uygulamak muhtemelen daha iyidir.

import java.util.ArrayList; 

import android.content.Context; 
import android.graphics.Bitmap; 
import android.graphics.Bitmap.Config; 
import android.graphics.Matrix; 
import android.graphics.PointF; 
import android.util.AttributeSet; 
import android.util.FloatMath; 
import android.util.Log; 
import android.view.MotionEvent; 
import android.view.View; 
import android.view.View.OnTouchListener; 
import android.widget.FrameLayout; 
import android.widget.ImageView; 
import android.widget.ImageView.ScaleType; 


public class TouchContainer extends FrameLayout implements OnTouchListener { 

    // constants 
    private static final Config DEFAULT_COLOR_DEPTH = Bitmap.Config.ARGB_4444; 
    private static final String TAG = "TouchContainer"; 

    // fields 
    private ArrayList<ImageView> items; 

    public TouchContainer(Context ctx) { 
     this(ctx, null); 
    } 

    public TouchContainer(Context ctx, AttributeSet attrs) { 
     super(ctx, attrs); 

     initializeViews(); // initialize some sample Bitmaps 
    } 

    /** 
    * This method is just to make an example 
    */ 
    protected void initializeViews() { 
     ScaleType scaleType = ScaleType.MATRIX; 

     // array needs to be created here if used in XML 
     items = new ArrayList<ImageView>(); 


     ArrayList<Bitmap> sampleBitmaps = new ArrayList<Bitmap>(); 
     // here you should add some bitmaps to the Array that will then be displayed in the container 
     // e.g. sampleBitmaps.add(blabla I'm a bitmap) :-) 

     ImageView iv = null; 
     boolean firstLoop = true; 

     for (Bitmap bitmap : sampleBitmaps) { 
      // Load the bitmaps into imageviews 
      iv = new ImageView(getContext()); 
      iv.setImageBitmap(bitmap); 
      iv.setScaleType(scaleType); 
      if (firstLoop) { 
       // add the touch listener to the first image view that is stored in the ArrayList 
       iv.setOnTouchListener(this); 
       firstLoop = false; 
      } 

      // add view to the FrameLayout 
      this.addView(iv); 

      // add the imageview to the array 
      items.add(iv); 
     } 

    } 



    protected void transformImages(Matrix matrix) { 
     for (ImageView image : items) { 
      image.setImageMatrix(matrix); 
     } 

    } 




    Matrix matrix = new Matrix(); 
    Matrix savedMatrix = new Matrix(); 

    // states 
    static final int NONE = 0; 
    static final int DRAG = 1; 
    static final int ZOOM = 2; 
    int mode = NONE; 
    static final int CLICK = 3; 


    PointF start = new PointF(); 
    PointF mid = new PointF(); 
    float oldDist = 1f; 

    public boolean onTouch(View v, MotionEvent event) { 


     switch (event.getAction() & MotionEvent.ACTION_MASK) { 
     case MotionEvent.ACTION_DOWN: 
     savedMatrix.set(matrix); 
     start.set(event.getX(), event.getY()); 
     Log.d(TAG, "mode=DRAG"); 
     mode = DRAG; 
     break; 
     case MotionEvent.ACTION_POINTER_DOWN: 
     oldDist = spacing(event); 
     Log.d(TAG, "oldDist=" + oldDist); 
     if (oldDist > 10f) { 
      savedMatrix.set(matrix); 
      midPoint(mid, event); 
      mode = ZOOM; 
      Log.d(TAG, "mode=ZOOM"); 
     } 
     break; 
     case MotionEvent.ACTION_UP: 
      // figure out if user clicked 
      mode = NONE; 
      int xDiff = (int) Math.abs(event.getX() - start.x); 
      int yDiff = (int) Math.abs(event.getY() - start.y); 
      if (xDiff < CLICK && yDiff < CLICK) 
       performClick(); 
      break; 
     case MotionEvent.ACTION_POINTER_UP: 
     mode = NONE; 
     Log.d(TAG, "mode=NONE"); 
     break; 
     case MotionEvent.ACTION_MOVE: 
     if (mode == DRAG) { 

      matrix.set(savedMatrix); 
      matrix.postTranslate(event.getX() - start.x, 
        event.getY() - start.y); 
     } 
     else if (mode == ZOOM) { 
      float newDist = spacing(event); 
      Log.d(TAG, "newDist=" + newDist); 
      if (newDist > 10f) { 
       matrix.set(savedMatrix); 
       float scale = newDist/oldDist; 
       matrix.postScale(scale, scale, mid.x, mid.y); 
      } 
     } 
     break; 
     } 


     transformImages(matrix); 


     return true; 
    } 




     private float spacing(MotionEvent event) { 
      float x = event.getX(0) - event.getX(1); 
      float y = event.getY(0) - event.getY(1); 
      return FloatMath.sqrt(x * x + y * y); 
     } 


     private void midPoint(PointF point, MotionEvent event) { 
      float x = event.getX(0) + event.getX(1); 
      float y = event.getY(0) + event.getY(1); 
      point.set(x/2, y/2); 
     } 





} 
İlgili konular