2012-05-02 21 views
5

Estoy tratando de crear un grupo de visualización que admita el paneo y el acercamiento de sus contenidos. Todo lo que pude encontrar en línea fueron ideas e implementaciones para hacerlo en un ImageView, pero nunca en un contenedor. Quiero mostrar un mapa y, además, quiero mostrar varios marcadores que son ImageButtons, por lo que el usuario puede tocarlos para obtener más información. Esto se logra en iOS mediante UIScrollView, pero no pude encontrar una alternativa en Android.Creación de un contenedor con capacidad de ampliación/capacidad de ampliación

Decidí usar un FrameView, así que pude establecer un ImageView con la imagen como fondo, y agregar un RelativeLayout en el que puedo agregar los ImageButtons y colocarlos usando los márgenes.

Tomé prestada parte de la implementación de TouchImageView here, pero he tenido complicaciones. Empecé con el paneo, y lo logré parcialmente, hace que el contenedor se mueva, pero el paneo funciona espantosamente, se agita mucho. Aquí está mi código:

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 
      } 

     }); 
    } 

Todas las ideas son muy apreciados.

editar: la inestabilidad parece ser la causa porque cuando se mueve, deltaX y deltaY alternan entre números positivos y negativos, verificando LogCat ... todavía no estoy seguro de por qué. Esto es causado por la variable curr que da valores diferentes cada vez, pero en lugar de ser consistentes, parecen como si el dedo se moviera hacia adelante y hacia atrás en lugar de solo hacia delante. Por ejemplo, en lugar de curr.x es 0,1,2,3,4, etc., es 0,1,0,5,2,1,5, etc. No estoy seguro de por qué tampoco.

+0

¿Alguna vez encontró una solución a esto? Estoy buscando exactamente lo mismo. Un mapa de zoom/panorámica con botones – 0xSina

+0

Oye, lo siento, dejé la compañía hace un tiempo y no puedo proporcionar el código. Encontré alguna solución, pero no puedo recordar cómo lo hice. –

Respuesta

0

tengo una solución que funciona con algunos requisitos previos:

  • los artículos en el contenedor deben ser de tipo ImageView
  • Todas las imágenes tienen que ser del mismo tamaño con el fin de enfocar igualmente

Los elementos del contenedor se pueden ampliar y panoramizar (pero no al mismo tiempo). El código también es capaz de determinar si un usuario ha hecho clic en lugar de moverse o acercarse. Las ImageViews se almacenan en una ArrayList en FrameLayout y se escalan y mueven juntas. Algunas partes de este código están tomadas de un artículo muy bueno en ZDNet por Ed Burnette (Link), que está tomado del muy buen libro de Android "Hello, Android".

Echa un vistazo a este código. Puede usar esta clase como diseño en cualquier actividad. Incluso debería poder usarlo en el XML. Por ahora hay un método initializeViews() que se llama en el constructor donde se pueden codificar las imágenes que deben cargarse cuando se crea el diseño. Debe agregar algunos mapas de bits en este método después de la línea "ArrayList sampleBitmaps = new ArrayList();" Para uso real, probablemente sea mejor implementar un método addImageView (elemento ImageView) donde pueda agregar vistas dinámicamente.

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





}