2011-01-25 17 views
20

Ho uno HorizontalScrollView che contiene uno RelativeLayout. Questo layout è vuoto nell'XML e viene popolato da Java nell'onCreate.Come scorrere a scorrimento di un HorizontalScrollView

Vorrei che questa vista di scorrimento fosse inizialmente da qualche parte nel mezzo dello RelativeLayout, che è molto più grande dello schermo.

Ho provato mHorizScrollView.scrollTo(offsetX, 0); che non funziona. Non so cosa c'è di sbagliato in questo.

Potrei postare il codice, ma non è veramente rilevante. Ciò che importa è che tutto sia fatto a livello di programmazione (deve: s), e che la posizione iniziale di HorizontalScrollView deve essere impostata a livello di programmazione.

Grazie per la lettura. Per favore dimmi se hai bisogno di maggiori dettagli o se questo non è abbastanza chiaro.

risposta

24

ho scoperto che se si extend il HorizontalScrollView e ignorare la onLayout, è possibile in modo pulito scorrere, dopo la chiamata super per onLayout:

MyScrollView extends HorizontalScrollView { 
    protected void onLayout (boolean changed, int l, int t, int r, int b) { 
     super.onLayout(changed, l, t, r, b); 
     this.scrollTo(wherever, 0); 
    } 
} 

EDIT: per lo scorrimento di inizio oppure fine è possibile utilizzare:

this.fullScroll(HorizontalScrollView.FOCUS_RIGHT/FOCUS_LEFT); 

invece di

this.scrollTo(wherever, 0); 
0

La funzione scrollTo dovrebbe funzionare. Qual è il layout_width dell'HSV e la vista al suo interno?

+1

Credo che questo sia un problema di temporizzazione. Le viste all'interno dell'HSV vengono aggiunte in fase di esecuzione (da onCreate) e il layout_width dell'HSV è fill_parent. MHSV.scrollTo() viene chiamato da onStart. –

15

Per verificare se si tratta di un problema di temporizzazione (che credo sia), anziché chiamare scrollTo() in onStart, chiamare postDelayed() con un Runnable che chiama scrollTo, con un ritardo di circa 30.

+1

Ciò ha confermato che si tratta, in effetti, di un problema di temporizzazione. C'è un modo più pulito per fare questo, di un Runnable post-inoltrato? –

+1

Probabilmente potresti creare una sottoclasse di HorizontalScrollView, aggiungere un campo che indica che lo scorrimento è necessario e quindi eseguire lo scorrimento alla fine della prossima chiamata a onLayout() (o forse su computeScroll() o qualche altro metodo). Penso che usare PostDelayed sia più semplice. –

+0

Giusto. Grazie ancora. –

1

Il problema è che la vista non ha ancora una dimensione. Il metodo Clean per eseguire questa operazione consiste nell'implementare onSizeChanged di ScrollView per inviare un messaggio a un handler nella propria attività al fine di notificare all'attività che la visualizzazione ha una dimensione e che lo scorrimento è possibile.

+0

Questo sembra davvero buono ma non funziona. Ho creato una classe che estende HorizontalScrollView e implementa onSizeChanged. Quando viene richiamato questo callback, richiama un metodo nell'attività che esegue lo scorrimento. Tuttavia, lo scorrimento non funziona. Funziona solo se è posticipato. –

0

La funzione onSizeChanged dovrebbe funzionare. Quello che non riesci a capire è che l'onSizeChanged dovrebbe inviare un messaggio a un Handler della tua attività e non alcuna funzione di callback, perché un gestore eseguirà il codice nel thread dell'interfaccia utente. Non è possibile eseguire operazioni di interfaccia utente al di fuori di esso. Dai un'occhiata ai gestori.

+1

onSizeChanged deve essere chiamato nel thread dell'interfaccia utente perché quando ho chiamato scrollTo da onSizeChanged, non si è lamentato. –

1

Utilizzare view.post e scrivere scrollTo (x, y) all'interno del metodo run. Questo è il modo per invalidare la visualizzazione nel metodo post come da documento API Android.

+0

Ho appena sostituito il mio postDelayed con un .post e funziona come un incantesimo. Proprio robusto come un ascoltatore che viene attivato _after_ la vista è stata allegata. Io lo uso per accedere alle dimensioni di una vista in quanto questa è disponibile solo dopo essere stata allegata allo schermo e misurata. – slott

9

Un approccio migliore sarebbe utilizzare ViewTreeObserver per osservare i layout.

View interestedInView; 
onCreate(){ 
    //Code 

    //Observe for a layout change 
    ViewTreeObserver viewTreeObserver = interestedInView.getViewTreeObserver(); 
    if (viewTreeObserver.isAlive()) { 
    viewTreeObserver.addOnGlobalLayoutListener(new OnGlobalLayoutListener() { 
     @Override 
     public void onGlobalLayout() { 
     //REMOVE THE VIEWTREE OBSERVER 
     //interestedInView is ready for size and position queries because it has been laid out 
     } 
    }); 
    } 
} 
+0

Grazie per il suo aiuto funziona per me, ma ho una domanda richiede più elaborazione poi postdayay (nuovo Runnable() ....) – MGD

+1

Beh, se stai prendendo tempo di esecuzione, la risposta è sì, perché sei aggiungendo un nuovo listener e rimuovendolo quindi. Ma è così minimo che non conterebbe. E vale la robustezza dell'approccio. –

+0

Ora sto usando ViewTreeObserver e sta funzionando per me, per favore dimmi se è meno efficiente o cosa ??? – MGD

22
public void autoSmoothScroll() { 

     final HorizontalScrollView hsv = (HorizontalScrollView) view.findViewById(R.id.horiscroll); 
     hsv.postDelayed(new Runnable() { 
      @Override 
      public void run() { 
       //hsv.fullScroll(HorizontalScrollView.FOCUS_RIGHT); 
       hsv.smoothScrollBy(500, 0); 
      } 
     },100); 
    } 
Problemi correlati