2010-10-05 17 views
11

Me gustaría tener una distribución lineal con una sección de encabezado en la parte superior y una vista web a continuación. El encabezado será corto y la vista web puede ser más larga y más ancha que la pantalla.vista de desplazamiento bidireccional

¿Cuál es la mejor manera de obtener desplazamiento horizontal y vertical? ¿Es un ScrollView anidado dentro de un HorizontalScrollView una buena idea?

Respuesta

8

Es un ScrollView anidado dentro de un HorizontalScrollVer una buena idea?

Sí, y no.

Sí, entiendo que ScrollView y HorizontalScrollView se pueden anidar.

No, AFAIK, ni ScrollView ni HorizontalScrollView funcionan con WebView.

Le sugiero que tenga su ajuste WebView en la pantalla.

+1

lo que puedo decir con certeza que un ScrollView y HorizontalScrollView se pueden anidar como he hecho, pero la experiencia del usuario es pobre, ya que puede ser difícil culto para hacer que se desplace en la dirección que desee, y no hay interpretación diagonal, ya sea que obtenga todos los movimientos verticales u horizontales. – Blumer

+0

"tenga su WebView en forma en la pantalla". Lamentablemente no tengo forma de hacer eso :( –

+0

@Blumer Me di cuenta. Eso es aceptable para mí, pero no es óptimo. –

-2

Sé que ha aceptado su respuesta, pero puede ser que esto le dé una idea.

<?xml version="1.0" encoding="utf-8"?> 

<ScrollView 
xmlns:android="http://schemas.android.com/apk/res/android" 
android:layout_width="fill_parent" 
android:layout_height="fill_parent" 
> 
<LinearLayout 
android:layout_width="fill_parent" 
android:layout_height="fill_parent" 
> 

<RelativeLayout 
android:layout_width="fill_parent" 
android:layout_height="fill_parent" 
> 
<HorizontalScrollView 
    android:layout_alignParentBottom="true" 
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent" 
> 
<ImageView 

android:src="@drawable/device_wall" 
android:scaleType="center" 
android:layout_width="fill_parent" 
android:layout_height="fill_parent" 
/> 
</HorizontalScrollView> 
</RelativeLayout> 
</LinearLayout> 
</ScrollView> 
+0

Parece el reverso de * "ScrollView anidado en el interior un HorizontalScrollView "*. ¿Hay algo que me falta? –

+0

Sí, ¿y qué demonios están haciendo LinearLayout y RelativeLayout en esta solución? A menos que estén cumpliendo algún tipo de propósito inexplicable, deben eliminarse para mantener la jerarquía de vista lo más plana posible. – SilithCrowe

6

hay otra manera. moddified HorizontalScrollView como un contenedor para ScrollView. normal HorizontalScrollView cuando los eventos de captura de contacto no los reenvían a ScrollView y solo puede desplazarse hacia un lado en el tiempo. aquí está la solución:

package your.package; 

import android.widget.HorizontalScrollView; 
import android.widget.ScrollView; 
import android.view.MotionEvent; 
import android.content.Context; 
import android.util.AttributeSet; 

public class WScrollView extends HorizontalScrollView 
{ 
    public ScrollView sv; 
    public WScrollView(Context context) 
    { 
     super(context); 
    } 

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

    public WScrollView(Context context, AttributeSet attrs, int defStyle) 
    { 
     super(context, attrs, defStyle); 
    } 

    @Override public boolean onTouchEvent(MotionEvent event) 
    { 
     boolean ret = super.onTouchEvent(event); 
     ret = ret | sv.onTouchEvent(event); 
     return ret; 
    } 

    @Override public boolean onInterceptTouchEvent(MotionEvent event) 
    { 
     boolean ret = super.onInterceptTouchEvent(event); 
     ret = ret | sv.onInterceptTouchEvent(event); 
     return ret; 
    } 
} 

usando:

@Override public void onCreate(Bundle savedInstanceState) 
    { 
     super.onCreate(savedInstanceState); 

/*BIDIRECTIONAL SCROLLVIEW*/ 
     ScrollView sv = new ScrollView(this); 
     WScrollView hsv = new WScrollView(this); 
     hsv.sv = sv; 
/*END OF BIDIRECTIONAL SCROLLVIEW*/ 

     RelativeLayout rl = new RelativeLayout(this); 
     rl.setBackgroundColor(0xFF0000FF); 
     sv.addView(rl, new LayoutParams(500, 500)); 
     hsv.addView(sv, new LayoutParams(WRAP_CONTENT, MATCH_PARENT /*or FILL_PARENT if API < 8*/)); 
     setContentView(hsv); 
    } 
+2

Lo curioso es que el desplazamiento vertical ya no funciona. –

+0

¡Puedo confirmar que esto funciona! En mi versión, tengo una vista que contiene desplazamientos X e Y anidados. Anulo el 'onTouchEvent' y' onInterceptTouchEvent' de View y reenvío el objeto MotionEvent a ambas vistas de desplazamiento, tal como se describe en esta respuesta. Experiencia suave, en ambas direcciones. – sulai

+1

Para hacer que funcione, tuve que adaptarme a TouchEvent para llamar SIEMPRE sv.onTouchEvent, y modifiqué el valor de retorno a verdadero. Tenga en cuenta también que debe extender la vista exterior. En mi caso, tenía unScrollView horizontal anidado en un ScrollView (vertical), así que tuve que extender el vertical. – jeroent

2

Hay una solución fácil: En la actividad que obtener una referencia a la ScrollView exterior (Voy a asumir una ScrollView vertical) y una referencia al primer hijo de esa vista de desplazamiento.

Scrollview scrollY = (ScrollView)findViewById(R.id.scrollY); 
LinearLayout scrollYChild = (LinearLayout)findViewById(R.id.scrollYChild); 

@Override 
public boolean dispatchTouchEvent(MotionEvent event) { 
    scrollYChild.dispatchTouchEvent(event); 
    scrollY.onTouchEvent(event); 
    return true; 
} 

Se podría argumentar que esta solución es un poco hacky. ¡Pero me ha funcionado muy bien en varias aplicaciones!

3

Realicé búsquedas muy largas para hacer esto y finalmente encontré este hilo aquí. wasikuss' answer estuvo bastante cerca de la solución, pero aun así no funcionó correctamente. Así es como funciona muy bien (al menos para mí (Android 2.3.7)). Espero que funcione en cualquier otra versión de Android también.

Crear una clase llamada VScrollView:

package your.package.name; 

import android.content.Context; 
import android.util.AttributeSet; 
import android.view.MotionEvent; 
import android.widget.HorizontalScrollView; 
import android.widget.ScrollView; 


public class VScrollView extends ScrollView { 
    public HorizontalScrollView sv; 

    public VScrollView(Context context) { 
     super(context); 
    } 

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

    public VScrollView(Context context, AttributeSet attrs, int defStyle) { 
     super(context, attrs, defStyle); 
    } 

    @Override 
    public boolean onTouchEvent(MotionEvent event) { 
     super.onTouchEvent(event); 
     sv.dispatchTouchEvent(event); 
     return true; 
    } 

    @Override 
    public boolean onInterceptTouchEvent(MotionEvent event) { 
     super.onInterceptTouchEvent(event); 
     sv.onInterceptTouchEvent(event); 
     return true; 
    } 
} 

Su diseño debe verse como:

<your.package.name.VScrollView 
    android:id="@+id/scrollVertical" 
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent" > 

    <HorizontalScrollView 
     android:id="@+id/scrollHorizontal" 
     android:layout_width="fill_parent" 
     android:layout_height="wrap_content" > 

     <TableLayout 
      android:id="@+id/table" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:clickable="false" 
      android:stretchColumns="*" > 
     </TableLayout> 
    </HorizontalScrollView> 
</your.package.name.VScrollView> 

En su actividad, usted debe hacer algo como:

hScroll = (HorizontalScrollView) findViewById(R.id.scrollHorizontal); 
vScroll = (VScrollView) findViewById(R.id.scrollVertical); 
vScroll.sv = hScroll; 

. .. y así es como funciona. Al menos para mi.

+3

¿Admite esto el desplazamiento en diagonal? –

1

Tarde para responder, pero con suerte podría ser útil para alguien. Puede consultar droid-uiscrollview. Esto se basa en gran medida en la respuesta @MrCeeJ's, pero parecía tener muchos problemas para obtener el contenido real. De ahí saqué la última fuente de HorizontalScrollView & ScrollView para crear droid-uiscrollview. Hay unos pocos todo's izquierda que no he tenido tiempo de terminar, pero no son suficientes para obtener el contenido para desplazarse en sentido horizontal & verticalmente al mismo tiempo enter image description here

1

he probar ambos wasikuss y user1684030 soluciones y yo tuve que adaptarlos debido a un registro de advertencia: HorizontalScrollView: Invalid pointerId=-1 in onTouchEvent, y porque no era partidario de esta necesidad de crear 2 vistas de desplazamiento.

Así que aquí está mi clase:

public class ScrollView2D extends ScrollView { 

    private HorizontalScrollView innerScrollView; 

    public ScrollView2D(Context context) { 
     super(context); 

     addInnerScrollView(context); 
    } 

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


    @Override 
    protected void onFinishInflate() { 
     super.onFinishInflate(); 

     if (getChildCount() == 1) { 
      View subView = getChildAt(0); 
      removeViewAt(0); 
      addInnerScrollView(getContext()); 
      this.innerScrollView.addView(subView); 
     } else { 
      addInnerScrollView(getContext()); 
     } 
    } 

    @Override 
    public boolean onTouchEvent(MotionEvent event) { 
     boolean handled = super.onTouchEvent(event); 
     handled |= this.innerScrollView.dispatchTouchEvent(event); 
     return handled; 
    } 

    @Override 
    public boolean onInterceptTouchEvent(MotionEvent event) { 
     super.onInterceptTouchEvent(event); 
     return true; 
    } 


    public void setContent(View content) { 
     if (content != null) { 
      this.innerScrollView.addView(content); 
     } 
    } 


    private void addInnerScrollView(Context context) { 
     this.innerScrollView = new HorizontalScrollView(context); 
     this.innerScrollView.setHorizontalScrollBarEnabled(false); 
     addView(this.innerScrollView); 
    } 

} 

Y cuando se utiliza en XML, que no tienen nada que ver si el contenido de este punto de vista de desplazamiento se establece aquí. De lo contrario, solo necesita llamar al método setContent(View content) para que este ScrollView2D sepa cuál es su contenido.

Por ejemplo:

// Get or create a ScrollView2D. 
ScrollView2D scrollView2D = new ScrollView2D(getContext()); 
scrollView2D.setLayoutParams(new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); 
addView(scrollView2D); 

// Set the content of scrollView2D. 
RelativeLayout testView = new RelativeLayout(getContext()); 
testView.setBackgroundColor(0xff0000ff); 
testView.setLayoutParams(new ViewGroup.LayoutParams(2000, 2000)); 
scrollView2D.setContent(testView); 
0

Durante un tiempo he estado tratando de soluciones de aquí, pero el que funcionó mejor todavía tenía un problema: Se comió todo caso, ninguno fue lo que a través de los elementos dentro de el scroller

Así que tengo ... otra respuesta, en Github y bien comentado, al menos, con suerte: https://github.com/Wilm0r/giggity/blob/master/app/src/main/java/net/gaast/giggity/NestedScroller.java

Como todas las soluciones, es un HorizontalScrollview anidada (exterior) + ScrollView (interior), con el eventos de recepción externa de Android, y el interior solo los recibe internamente desde la vista exterior.

Sin embargo, estoy confiando en ScrollViews para decidir si un evento táctil es interesante y hasta que lo acepten, no hacer nada, por lo que los toques (es decir, tocar para abrir enlaces/etc) aún pueden llegar a elementos secundarios.

(También la vista admite pellizcar para hacer zoom que necesitaba.)

En el desplazador exterior:

@Override 
public boolean onInterceptTouchEvent(MotionEvent event) 
{ 
    if (super.onInterceptTouchEvent(event) || vscroll.onInterceptTouchEventInt(event)) { 
     onTouchEvent(event); 
     return true; 
    } 
    return false; 
} 

@Override 
public boolean onTouchEvent(MotionEvent event) 
{ 
    super.onTouchEvent(event); 
    /* Beware: One ugliness of passing on events like this is that normally a ScrollView will 
     do transformation of the event coordinates which we're not doing here, mostly because 
     things work well enough without doing that. 
     For events that we pass through to the child view, transformation *will* happen (because 
     we're completely ignoring those and let the (H)ScrollView do the transformation for us). 
    */ 
    vscroll.onTouchEventInt(event); 
    return true; 
} 

VScroll aquí es el "InnerScroller", una subclase de ScrollView, con algunos cambios en el manejo de eventos: He hecho algunas cosas terribles para asegurar eventos de toque directamente entrantes desde Android se descartan, y en su lugar sólo les llevará desde la clase externa - y sólo entonces pasan los de la superclase:

@Override 
    public boolean onInterceptTouchEvent(MotionEvent event) { 
     /* All touch events should come in via the outer horizontal scroller (using the Int 
      functions below). If Android tries to send them here directly, reject. */ 
     return false; 
    } 

    @Override 
    public boolean onTouchEvent(MotionEvent event) { 
     /* It will still try to send them anyway if it can't find any interested child elements. 
      Reject it harder (but pretend that we took it). */ 
     return true; 
    } 

    public boolean onInterceptTouchEventInt(MotionEvent event) { 
     return super.onInterceptTouchEvent(event); 
    } 

    public boolean onTouchEventInt(MotionEvent event) { 
     super.onTouchEvent(event); 
    } 
+0

Por favor agregue algunos de los códigos relevantes de su github en su respuesta aquí. –

Cuestiones relacionadas