2010-10-05 18 views
11

Mi piacerebbe avere una visualizzazione lineare con una sezione di intestazione in alto e una webview di seguito. L'intestazione sarà breve e la visualizzazione Web potrebbe essere più lunga e più ampia dello schermo.vista scorrimento bidirezionale

Qual è il modo migliore per ottenere lo scorrimento orizzontale e verticale? Una ScrollView annidata all'interno di HorizontalScrollView è una buona idea?

risposta

8

Un ScrollView annidato all'interno di HorizontalScrollView è una buona idea?

Sì, e no.

Sì, la mia comprensione è che ScrollView e HorizontalScrollView possono essere nidificati.

No, AFAIK, né ScrollViewHorizontalScrollView funzionano con WebView.

Suggerisco di avere lo WebView in forma sullo schermo.

+1

posso dire per certo che uno ScrollView e HorizontalScrollView possono essere nidificate come ho fatto, ma l'esperienza dell'utente è scarsa in quanto può essere diversa culto per farlo scorrere nella direzione in cui lo si desidera, e non vi è alcuna interpretazione diagonale - si ottiene tutto il movimento verticale o tutto orizzontale. – Blumer

+0

"visualizzare WebView sullo schermo." Purtroppo non ho modo di farlo :( –

+0

@Blumer ho notato.Questo è accettabile per me ma non ottimale –

-2

So che hai accettato la tua risposta ma potrebbe essere questo potrebbe darti un'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

Sembra il contrario di * "ScrollView annidato all'interno a HorizontalScrollView "*. C'è qualcosa che mi manca? –

+0

Sì, e quali sono nel mondo le soluzioni LinearLayout e RelativeLayout in questa soluzione? A meno che non stiano servendo una specie di scopo inspiegabile, dovrebbero essere rimossi per mantenere la gerarchia della vista quanto più piatta possibile. – SilithCrowe

8

Due anni più in basso la linea penso che la comunità open source potrebbe avere in vostro soccorso: 2D Scroll View.

Modifica: il collegamento non funziona più ma here is a link to an old version of the blogpost;

+12

3 anni più avanti sulla linea e il collegamento è andato – jiduvah

+1

@jiduvah collegamento corretto –

+1

Grazie! Piacere di vedere la gente importa :) I collegamenti – MrCeeJ

6

c'è un altro modo. modificato HorizontalScrollView come wrapper per ScrollView. normale HorizontalScrollView quando gli eventi tocco catch non li inoltrano a ScrollView e si può solo scorrere in un modo alla volta. qui è la soluzione:

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

utilizzando:

@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

La cosa divertente è che lo scorrimento verticale non funziona più. –

+0

Posso confermare che funziona! Nella mia versione ho una vista contenente scroll X e Y annidati. Sovrascrivo la vista 'onTouchEvent' e 'onInterceptTouchEvent' e inoltro l'oggetto MotionEvent in entrambe le scorrie viste, proprio come descritto in questa risposta. Esperienza fluida, entrambe le direzioni. – sulai

+1

Per farlo funzionare ho dovuto adattare toTouchEvent a SEMPRE chiamare sv.onTouchEvent e ho modificato il valore restituito su true. Nota anche che devi estendere la vista esterna. Nel mio caso ho avuto uno scrolling orizzontale in uno ScrollView (verticale), quindi ho dovuto estendere quello verticale. – jeroent

2

C'è una soluzione semplice: In te attività ottenere un riferimento al ScrollView esterno (ho intenzione di assumere una ScrollView verticale) e un riferimento al primo figlio di quella vista di scorrimento.

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

Si potrebbe obiettare che questa soluzione è un po 'hacky. Ma ha funzionato benissimo per me in diverse applicazioni!

3

Ho cercato molto a lungo per fare questo lavoro e finalmente ho trovato questo thread qui. wasikuss' answer è arrivato abbastanza vicino alla soluzione, ma ancora non ha funzionato correttamente. Ecco come funziona molto bene (almeno per me (Android 2.3.7)). Spero, funzioni anche su qualsiasi altra versione di Android.

Creare una classe chiamata 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; 
    } 
} 

Il layout dovrebbe essere simile:

<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> 

Nella vostra attività, si dovrebbe fare qualcosa di simile:

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

. .. ed è così che funziona Almeno per me.

+3

Questo supporta lo scorrimento diagonale? –

1

In ritardo per rispondere, ma si spera potrebbe essere utile a qualcuno. Puoi dare un'occhiata allo droid-uiscrollview. Questo è fortemente basato sulla risposta @MrCeeJ's, ma mi sembra che abbia molti problemi a ottenere il rendering del contenuto reale. Quindi ho inserito l'ultima fonte da HorizontalScrollView & ScrollView per creare droid-uiscrollview. Ci sono alcuni todo's sinistra che non ho ottenuto intorno a finire, ma lo fa sono sufficienti per ottenere contenuti per scorrere sia in orizzontale che in verticale & allo stesso tempo enter image description here

1

Ho provare entrambi wasikuss e user1684030 soluzioni e io dovuto adattarli a causa di un registro di avviso: HorizontalScrollView: Invalid pointerId=-1 in onTouchEvent e perché non ero fan di questa necessità di creare 2 viste di scorrimento.

Così qui è la mia classe:

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

} 

E quando lo si utilizza in XML, non hai niente da fare se il contenuto di questa vista di scorrimento si trova in qui. Altrimenti, è sufficiente chiamare il metodo setContent(View content) per consentire a questo ScrollView2D di sapere qual è il suo contenuto.

Per esempio:

// 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

Per un po 'ho cercato soluzioni da qui, ma quello che ha funzionato meglio ancora avuto un problema: E' mangiato tutti gli eventi, nessuno stavano facendo attraverso ad elementi all'interno lo scroller.

Così ho ... ancora un'altra risposta, in Github e ben commentato, almeno si spera: https://github.com/Wilm0r/giggity/blob/master/app/src/main/java/net/gaast/giggity/NestedScroller.java

Come tutte le soluzioni, è un HorizontalScrollview annidato (esterno) + ScrollView (interno), con il gli eventi tattili di ricezione esterni da Android e quelli interni che li ricevono solo internamente dalla vista esterna.

Tuttavia, mi sto affidando alle ScrollView per decidere se un evento di tocco è interessante e fino a quando non lo accettano, non fare nulla che tocchi (ad esempio toccare per aprire i collegamenti/etc) può ancora farlo agli elementi figlio.

(Anche la vista supporta il pizzico per lo zoom di cui avevo bisogno.)

Nella scroller esterno:

@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 qui è la "InnerScroller", una sottoclasse di ScrollView, con alcune modifiche alla gestione degli eventi: Ho fatto alcune cose terribili per assicurare direttamente eventi di tocco in arrivo da Android vengono scartati, e invece sarà solo portarli dalla classe esterna - e solo allora passare quelli al superclasse:

@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

Per favore aggiungi un po 'del codice pertinente dal tuo gitub alla tua risposta qui. –

Problemi correlati