2012-04-03 10 views
12

Quindi ho cercato in alto e in basso ma non sono riuscito a trovare una risposta alla mia domanda. Quello di cui ho fondamentalmente bisogno è il comportamento fornito da ViewFlipper o ViewPager di Android, ma voglio visualizzare parti delle viste sinistra e destra, per indicare all'utente che ci sono elementi da far scorrere, invece di avere la vista selezionata che occupa l'intero schermo.Android - Widget simile a un carosello che visualizza una parte degli elementi sinistro e destro

Vorrei anche aggiungere alcuni effetti alle viste di sinistra e di lato, come l'attenuazione e il ridimensionamento, quindi verso il basso un po '. È possibile farlo con il ViewFlipper o ViewPager di serie o devo distribuire il mio gruppo di visualizzazione, al flusso di copertina (http://www.inter-fuser.com/2010/01/android-coverflow-widget.html)?

(P.S. Non voglio usare il widget Galleria, quel componente fa schifo).

Questo è quello che ci serve per visualizzare una volta al punto di vista è selezionata (viste sinistra e destra sono ancora visualizzato):

view switcher

Lanciando a sinistra oa destra sarebbe transizione vista principale out, oscuramento e riducendola un po 'e facendo il contrario con la vista successiva o precedente.

+0

[Stai descrivendo questo?] (Http://stackoverflow.com/questions/9816371/how-to-use-multi-pane-layouts-with-viewpager) – adneal

+0

Close, eccetto che la vista selezionata non dovrebbe occupare l'intero schermo. Vedi modifica sopra con un'immagine che spiega il layout. – AngraX

risposta

16

Vorrei fornire un aggiornamento a chiunque desideri la stessa funzione. Sono stati fatti molti progressi per implementare questa funzionalità finora e ora la vista funziona esattamente come ne abbiamo bisogno.

ViewPager ha un metodo denominato setPageMargin(). Questo metodo può ricevere un valore negativo che farà sì che i frammenti/viste si sovrappongano l'un l'altro. Per arrivare al layout desiderato, abbiamo prima calcolato in modo dinamico i margini sinistro e destro di una percentuale dello schermo. Questo può essere fatto anche in modo statico, ma dato che ci rivolgeremo a una gamma di schermi di dimensioni diverse, questo sembra essere l'approccio migliore.

Successivamente impostiamo il margine della pagina di ViewPager su 2 volte la dimensione dei margini laterali. Questo fa sì che le viste si riavvicinino. Tuttavia, in questo momento, ci sarà più di una vista visualizzata dal ViewPager.

Tutto quello che resta da fare è applicare una trasformazione (scala) alle viste a sinistra e destra (Android 3.0+) o aggiungere alcuni margini attorno a loro per ridurle alla giusta dimensione (pre 3.0) .

OnPageChangeListener.onPageScrolled() può essere utilizzato per tracciare lo scorrimento di ViewPager. È possibile ottenere una trasformazione liscia . Il codice è simile al seguente:

private OnPageChangeListener onPageChangeListener = new OnPageChangeListener() { 

    @Override 
    public void onPageSelected(int position) { 
    } 

    @Override 
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { 

     // positionOffset varies from 0 to 1 and indicates how far the view is 
     // from the center of the ViewPager. When a view is selected (centered), this 
     // value is 0. 

     // Fades the text in an out while the ViewPager scrolls from one view to another. 
     // On our final design the text views are fixed to the center of the screen and 
     // do not scroll along with the views. 
     if (positionOffset < 0.5) { 
      setTextViewAlpha(1 - positionOffset * 2); 
     } else { 
      setTextViewAlpha((positionOffset - 0.5f) * 2); 
     } 

     // It's surprisingly complicated to get the current object being displayed by 
     // a ViewPager (there's no getCurrentObject method). ScaleableFragment is just 
     // a custom class to allow an adapter to cache it internally and also correctly 
     // manage a fragment's lifecycle and restore from a saved state. 
     ScaleableFragment sampleFragment = (ScaleableFragment) ((ShowHeroShotImageFragmentPagerAdapter) pager 
       .getAdapter()).getItem(position); 

     // Calculates by how much the current view will be scaled down. The RATIO_SCALE 
     // is 0.3 in our case, which makes the side views 70% of the size of the 
     // center view. When centered, the scale will be 1. When 
     // fully scrolled, the scale will be 0.7. 
     float scale = 1 - (positionOffset * RATIO_SCALE); 

     // Just a shortcut to findViewById(R.id.image).setScale(scale); 
     sampleFragment.scaleImage(scale); 


     // Now, if not in the last element, scale the next one up (in opposite direction). 
     if (position + 1 < pager.getAdapter().getCount()) { 
      sampleFragment = (ScaleableFragment) ((ShowHeroShotImageFragmentPagerAdapter) pager.getAdapter()) 
        .getItem(position + 1); 
      scale = positionOffset * RATIO_SCALE + (1 - RATIO_SCALE); 
      sampleFragment.scaleImage(scale); 
     } 
    } 

    // Once scrolling is done. Make sure the views are in the right scale (1 for center, 
    // 0.7 for sides). Required as the onPageScrolled() method does not guarantee it 
    // will interpolate to 1.0 precisely. 
    @Override 
    public void onPageScrollStateChanged(int state) { 
     if (state == ViewPager.SCROLL_STATE_IDLE) { 
      setTextViewAlpha(1); 
      ScaleableFragment sampleFragment = (ScaleableFragment) ((ShowHeroShotImageFragmentPagerAdapter) pager 
        .getAdapter()).getItem(pager.getCurrentItem()); 
      sampleFragment.scaleImage(1); 
      sampleFragment.enableClicks(); 

      if (pager.getCurrentItem() > 0) { 
       sampleFragment = (ScaleableFragment) ((ShowHeroShotImageFragmentPagerAdapter) pager.getAdapter()) 
         .getItem(pager.getCurrentItem() - 1); 
       sampleFragment.scaleImage(1 - RATIO_SCALE); 
       sampleFragment.disableClicks(); 
      } 

      if (pager.getCurrentItem() + 1 < pager.getAdapter().getCount()) { 
       sampleFragment = (ScaleableFragment) ((ShowHeroShotImageFragmentPagerAdapter) pager.getAdapter()) 
         .getItem(pager.getCurrentItem() + 1); 
       sampleFragment.scaleImage(1 - RATIO_SCALE); 
       sampleFragment.disableClicks(); 
      } 
     } 
    } 
}; 

Questo è tutto. Non ho pubblicato la soluzione completa, ma spero che questo sia sufficiente per far iniziare qualcun altro.

P.S. Su 3.0+ abilita l'accelerazione hardware. Senza di esso, lo scorrimento appariva instabile su una scheda Samsung Galaxy 10.1.

+0

Sto usando il metodo setPageMargin ma senza risultato in orizzontale, funziona solo in modalità verticale per qualche motivo che non riesco a capire a questo punto, il resto è abbastanza semplice, ma se non riesco a farlo funzionare in orizzontale, allora il mio approccio (come te di applicare un padding/margine alle viste non attive) allora questo è inutile. Ci sono altre cose che devo tenere in considerazione a parte il metodo setPageMargin per far funzionare tutto questo? –

+0

@Jorge Aguilar Davvero non posso dire senza guardare il codice sorgente. La nostra app è in modalità orizzontale e funziona perfettamente. – AngraX

+0

Sareste in grado di pubblicare il codice per ScaleableFragment? – Marche101

2

Bene, ecco una potenziale risposta che potrebbe essere vicina a quello che stai cercando, ma non esattamente quello che stai cercando: c'è un progetto chiamato ViewFlow che penso offre la possibilità di notificare all'utente che ci sono più viste tramite gli indicatori sullo schermo. Fornisce inoltre la possibilità di salvare le viste a sinistra e a destra della vista corrente, in modo da poter attirare il codice per renderne piccole parti riducendo sostanzialmente le visualizzazioni a schermo.

Modifica: Silly me; Dovrei leggere l'ultima domanda prima di rispondere. :) Non penso che tu possa farlo con ViewFlipper o Viewpager, sfortunatamente.

+0

Grazie comunque. Volevo evitare di sviluppare il mio widget. Forse il codice sorgente per ViewFlipper o ViewPager è comunque un buon inizio. – AngraX

1

Basta usare un ViewPager e giocare con la larghezza dei frammenti e dei margini. L'ho fatto e funziona bene.

3

Ne ho giocato un po 'e la mia soluzione è piuttosto semplice. Sto postando qui nel caso qualcuno sia interessato.

In primo luogo, il layout per ciascun frammento dovrebbe consentire alcuni spazi su entrambi i lati. il modo più semplice che ho trovato per farlo è usare pesi:

<LinearLayout 
    android:layout_width="0dp" 
    android:layout_height="match_parent" 
    android:layout_weight="0.1" /> 

<LinearLayout 
    android:layout_width="0dp" 
    android:layout_height="match_parent" 
    android:layout_weight="0.8" 
    android:orientation="vertical" > 

    <!-- fragment contents go here --> 

</LinearLayout> 

<LinearLayout 
    android:layout_width="0dp" 
    android:layout_height="match_parent" 
    android:layout_weight="0.1" /> 

questo lascerà un bel margine del 10% su entrambi i lati. Assicurati di non impostare uno sfondo su questi, poiché coprirà i frammenti vicini. Ora per il cercapersone: è necessario utilizzare margini negativi, come spiegato da AngraX, ma assicuratevi anche di precaricare i frammenti successivi, poiché sono visibili prima che si verifichino regolarmente. Ho ottenuto buoni risultati con questo:

mPager = (ViewPager) findViewById(R.id.pager); 
    mPager.setAdapter(mAdapter); 
    mPager.setPageMargin(getResources().getDisplayMetrics().widthPixels/-7); 
    mPager.setOffscreenPageLimit(2); 

il -7 valore lascia ai margini del frammento successivo visibile, giocare con la vostra composizione specifica. Raccomando anche di inquadrare ogni frammento.

Problemi correlati