2011-05-07 6 views
19

Efecto deseado Tengo un montón de pequeñas imágenes que me gustaría mostrar en una "pared" y luego permita que el usuario arroje esta pared en cualquier dirección y seleccione una imagen.buscando implementar una pared (¿GridView?) Que se sale de la pantalla y el usuario puede tocar para moverlo

idea inicial como una posible aplicación estaba pensando un GridView que es mayor que la pantalla puede mostrar - pero todos los ejemplos del uso de este widget indican que la galería no se extiende más allá del tamaño de la pantalla.

Pregunta ¿Cuál es el mejor artilugio que se debe usar para implementar el efecto deseado? Una muestra de código sería especialmente beneficiosa.

EDITAR ... si alguien tiene el código de ejemplo que me deja poner alrededor de 30 imágenes en una "pared" (tabla sería bueno) entonces voy a aceptar que como la respuesta. Tenga en cuenta que la "pared" debe parecer que se extiende más allá de los bordes de la pantalla y permite que el usuario use el dedo para arrastrar la "pared" hacia arriba, hacia la izquierda, hacia la derecha. Arrastrar debe estar en modo "forma libre". Un solo toque en una imagen lo selecciona y una devolución de llamada será detectable. He creado una recompensa por esta solución.

Respuesta

11

La solución es bastante simple, pero duele. Tuve que implementar exactamente esto dentro de un programa que hice recientemente.Sin embargo, hay algunas cosas trucos por las que tienes que moverte. Cabe señalar que las diferentes versiones del sistema operativo tienen diferentes experiencias. Se requiere cierta experiencia o un toque para hacer que esto funcione, ya que el dibujo a veces se ve negativamente afectado por este método. Mientras que I tengo una copia de trabajo, el código que proporciono no es para todos, y está sujeto a cualquier otro cambio o personalización que se haya realizado en su código.

  • conjunto android:layout_width a wrap_content
  • conjunto android:layout_height a wrap_content
  • En su código:
    • determinar el número de filas que tendrá.
    • divida el número de elementos por el número de filas.
    • agregar gridView. setStretchMode(NO_STRETCH);
    • agregar gridView. setNumColumns( número de columnas );
    • agregar gridView. setColumnWidth( una anchura en píxeles explícita );
  • para desplazarse:
    • Usted puede simplemente utilizar GridView. scrollBy() en su onTouchEvent()

Estos son los pasos. Todos son necesarios para que funcione. La clave es NO_STRETCH con un número explícito de columnas con un ancho específico. Se pueden proporcionar más detalles, si necesita una aclaración. Incluso puede usar un VelocityTracker o onFling para manejar el arrojamiento. Tengo snappingToPage habilitado en el mío. Con esta solución, ni siquiera es necesario anular onDraw() o onLayout(). Esas tres líneas de código eliminan la necesidad de una WebView o cualquier otra incrustación o anidación.

El desplazamiento bidireccional también es bastante fácil de implementar. Aquí hay una solución de código simple:

  1. Primero, en su clase, comience a rastrear las posiciones X e Y haciendo dos miembros de la clase. También agregue el seguimiento del estado;

    // Holds the last position of the touch event (including movement) 
    int myLastX; 
    int myLastY; 
    
    // Tracks the state of the Touch handling 
    final static private int TOUCH_STATE_REST = 0; 
    final static private int TOUCH_STATE_SCROLLING = 1; 
    int myState = TOUCH_STATE_REST; 
    
  2. En segundo lugar, asegúrese de comprobar si hay movimiento en sentido vertical, de esa manera usted todavía puede hacer clic o longclick las propias imágenes.

    @Override public boolean onInterceptTouchEvent(final MotionEvent ev) 
    {//User is already scrolling something. If we haven't interrupted this already, 
    // then something else is handling its own scrolling and we should let this be. 
    // Once we return TRUE, this event no longer fires and instead all goes to 
    // onTouch() until the next TouchEvent begins (often beginning with ACTION_DOWN). 
        if ((ev.getAction() == MotionEvent.ACTION_MOVE) 
        && (myState != TOUCH_STATE_REST)) 
         return false; 
    
    // Grab the X and Y positions of the MotionEvent 
        final float _x = ev.getX(); 
        final float _y = ev.getY(); 
        switch (ev.getAction()) 
        { case MotionEvent.ACTION_MOVE: 
          final int _diffX = (int) Math.abs(_x - myLastX); 
          final int _diffY = (int) Math.abs(_y - myLastY); 
    
          final boolean xMoved = _diffX > 0; 
          final boolean yMoved = _diffY > 0; 
          if (xMoved || yMoved) 
           myState = TOUCH_STATE_SCROLLING; 
          break; 
         case MotionEvent.ACTION_DOWN: 
         // Remember location of down touch 
          myLastX = _x; 
          myLastY = _y; 
          break; 
         case MotionEvent.ACTION_CANCEL: 
         case MotionEvent.ACTION_UP: 
          if (myState == TOUCH_STATE_SCROLLING) 
          // Release the drag 
           myState = TOUCH_STATE_REST; 
    
        } 
        //If we are not At Rest, start handling in our own onTouch() 
        return myState != TOUCH_STATE_REST; 
    } 
    
  3. Después de que el GridView sabe que se está desplazando, enviará todos los eventos de toque a onTouch. Haga su desplazamiento aquí.

    @Override public boolean onTouchEvent(final MotionEvent ev) 
    { 
        final int action = ev.getAction(); 
        final float x = ev.getX(); 
        final float y = ev.getY(); 
        final View child; 
    
        switch (action) 
        { 
         case MotionEvent.ACTION_DOWN: 
          //Supplemental code, if needed 
          break; 
         case MotionEvent.ACTION_MOVE: 
          // This handles Scrolling only. 
          if (myState == TOUCH_STATE_SCROLLING) 
          { 
           // Scroll to follow the motion event 
           // This will update the vars as long as your finger is down. 
           final int deltaX = (int) (myLastX - x); 
           final int deltaY = (int) (myLastY - y); 
           myLastX = x; 
           myLastY = y; 
           scrollBy(deltaX, deltaY); 
          } 
          break; 
         case MotionEvent.ACTION_UP: 
         // If Scrolling, stop the scroll so we can scroll later. 
          if (myState == TOUCH_STATE_SCROLLING) 
           myState = TOUCH_STATE_REST; 
          break 
         case MotionEvent.ACTION_CANCEL: 
         // This is just a failsafe. I don't even know how to cancel a touch event 
          myState = TOUCH_STATE_REST; 
        } 
    
    return true; 
    } 
    

Si supuesto, esta solución se mueve a X e Y al mismo tiempo. Si desea mover solo una dirección a la vez, puede diferenciar fácilmente al verificar la mayor de las diferencias X e Y. (es decir, Math.abs(deltaX) > Math.abs(deltaY)) A continuación se muestra una muestra parcial para un desplazamiento direccional, pero puede cambiar entre las direcciones X o Y.

3b.Cambiar esto en su OnTouch() si desea manejar una dirección a la vez:

  case MotionEvent.ACTION_MOVE: 
       if (myState == TOUCH_STATE_SCROLLING) 
       { 
        //This will update the vars as long as your finger is down. 
        final int deltaX = (int) (myLastX - x); 
        final int deltaY = (int) (myLastY - y); 
        myLastX = x; 
        myLastY = y; 

        // Check which direction is the bigger of the two 
        if (Math.abs(deltaX) > Math.abs(deltaY)) 
         scrollBy(deltaX, 0); 
        else if (Math.abs(deltaY) > Math.abs(deltaX)) 
         scrollBy(0, deltaY); 
        // We do nothing if they are equal. 
       } 
       break; 

FuzzicalLogic

+0

Me habría proporcionado una muestra completa, pero esas son las únicas 3 líneas que son importantes y pueden ser colocados en cualquier lugar. Tengo tres de tales GridViews y cada uno los coloca en un lugar diferente (uno en la declaración inicial, uno en un CursorAdapter, y uno en un método diferente que se llama desde varios lugares. –

+1

Y ... como nota al margen, esto tomó Me dio una semana de preguntas y preguntas. Estaba tan feliz cuando lo hice. –

+0

¿A qué se refiere mScroller en este contexto? Si elaboras un poco te otorgaré la recompensa. –

5

A GridView puede tener un contenido que se extiende más allá del tamaño de la pantalla, pero solo en la dirección vertical.

Pregunta: ¿Cuál es el mejor widget para usar para implementar el efecto deseado?
No hay widgets predeterminados (al menos antes de 3.0) que implementan desplazamiento 2D. Todos ellos implementan 1D (desplazamiento en una dirección) solamente. Lamentablemente, la solución a su problema no es tan fácil.

Usted podría:

  • Coloque un TableLayout dentro de una clase personalizada ScrollView, y manejar los eventos de toque a ti mismo. Esto le permitiría realizar una panorámica 2D adecuada, pero no sería tan bueno para conjuntos de datos grandes ya que no habría reciclaje de vistas
  • Modifique GridView si es posible para habilitar la funcionalidad de desplazamiento horizontal (probablemente la mejor solución si puede hacerlo))
  • Trate de poner un TableLayout dentro de un ScrollView (con layout_width="wrap_content), que se pone dentro de un HorizontalScrollView - aunque esto puede trabajar, no sería la solución óptima
  • hacer algo con OpenGL y proyecto de escalera a un lienzo - esto es cómo el Gallery 3D app predeterminado es su "pared de imágenes"
+0

que han comenzado una recompensa por una solución concreta –

+0

Siempre se puede mirar el código fuente Gallery3D - http://android.git.kernel.org/?p=platform/packages/apps/Gallery3D .git; a = resumen - hasta que alguien responda. –

+1

He tenido una idea de cómo se podría hacer con bastante facilidad, haré una demostración este fin de semana y veré si funciona. –

0

Creo que la única solución nativa de Android para esto es tener un WebView embebido en el que puede tener ese desplazamiento bidimensional (y por cierto es lo único que tiene esta capacidad).

Al presionar una imagen, puede controlar el comportamiento mediante una devolución de llamada de JavaScript a JAva.

Esto no es muy "bonito" pero ... es la única forma viable de hacer lo que quiere "de fábrica".

+0

webview es una idea interesante. Probablemente usaría esta idea como último recurso. Hasta ahora, todavía estoy en modo de investigación y la mejor "muestra" que he encontrado está aquí: http://stackoverflow.com/questions/3058164/android-scrolling-an-imageview –

+0

otra muestra de investigación que tal vez pueda ajustar para un muro de imágenes: http://blog.sephiroth.it/2011/04/04/imageview-zoom-and-scroll/ –

0

he implementado un GridView que anula los métodos onInterceptTouchEvent. Configuré OnTouchListener como se explica en Fuzzical Logic. Mi problema es que al configurar un OnTouchListener personalizado, ya no se puede hacer clic en los objetos de mi gridView. ¿Eso es porque el OnTouchListener predeterminado de un GridView llama aItemClickListener?

Me gustaría tener un GridView desplazable en 2 direcciones pero que todavía tiene objetos cliackable. ¿Debo implementar mi propio método para verificar si un toque coincide con un elemento o hay una manera más fácil de lograrlo?

Grodak

Cuestiones relacionadas