10

Ho un singolo nestedscrollview verticale che contiene una serie di recyclerview con un layout orizzontale layoutmanager. L'idea è molto simile a come appare il nuovo Play Store di Google. Sono in grado di renderlo funzionale ma non è affatto liscio. Ecco i problemi:NestedScrollView e Recycler orizzontaleView Scrolling liscio

1) L'elemento di riciclo orizzontale non riesce a intercettare l'evento di tocco il più delle volte anche se tocco direttamente su di esso. La vista di scorrimento sembra avere la precedenza per la maggior parte dei movimenti. È difficile per me avere un gancio sul movimento orizzontale. Questo UX è frustrante, perché ho bisogno di provare un paio di volte prima che funzioni. Se controlli il Play Store, è in grado di intercettare l'evento touch molto bene e funziona perfettamente. Ho notato che nel play store il modo in cui sono stati impostati è un gran numero di ricircoli orizzontali all'interno di una raccolta verticale. Nessuna vista a scorrimento.

2) L'altezza dei riquadri orizzontali deve essere impostata manualmente e non esiste un modo semplice per calcolare l'altezza degli elementi figli.

Ecco il layout che sto utilizzando:

<android.support.v4.widget.NestedScrollView 
    android:id="@+id/scroll" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:clipToPadding="false" 
    android:background="@color/dark_bgd" 
    app:layout_behavior="@string/appbar_scrolling_view_behavior"> 

    <LinearLayout 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:orientation="vertical"> 

     <LinearLayout 
      android:id="@+id/main_content_container" 
      android:layout_width="match_parent" 
      android:layout_height="wrap_content" 
      android:visibility="gone" 
      tools:visibility="gone" 
      android:orientation="vertical">     

       <android.support.v7.widget.RecyclerView 
        android:id="@+id/starring_list" 
        android:paddingLeft="@dimen/spacing_major" 
        android:paddingRight="@dimen/spacing_major" 
        android:layout_width="match_parent" 
        android:layout_height="180dp" /> 

Questo modello interfaccia utente è molto semplice e molto probabilmente utilizzato in molte applicazioni diverse. Ho letto molti SO in cui ppl dice che è una cattiva idea inserire una lista in una lista, ma è un modello di interfaccia utente molto comune e moderno usato in tutto il sito. Pensate all'interfaccia di netflix come ad una serie di liste di scroll orizzontali all'interno una lista verticale. Non c'è un modo semplice per realizzare questo?

immagine Esempio dal negozio:

Google Play Store

+0

La cosa strana è che ho il problema opposto: voglio che NestedScrollView permetta di scorrere verticalmente, ma il RecyclerView orizzontale prende gli eventi di tocco così quando inizio lo scorrimento verticale su di esso, non lo consente. Inoltre, se hai solo pochi elementi da mostrare, puoi utilizzare un semplice HorizontalScrollView con LinearLayout. –

risposta

13

Quindi il problema di scorrimento uniforme è stato risolto ora. È stato causato da un bug in NestedScrollView nella Libreria del supporto di progettazione (attualmente 23.1.1).

Si può leggere in merito alla questione e la soluzione semplice qui: https://code.google.com/p/android/issues/detail?id=194398

In breve, dopo aver eseguito una scappatella, il nestedscrollview non ha registrato un completo sul componente scroller e quindi è necessario un ulteriore ' ACTION_DOWN 'per rilasciare il parentedscrollview genitore dall'intercettare (mangiare) gli eventi successivi. Quindi, quello che è successo è stato se avessi provato a scorrere l'elenco dei tuoi figli (o il tuo viewpager), dopo un'avventura, il primo tocco rilasciasse il binding NSV genitore e i tocchi successivi funzionerebbero. Quello stava facendo davvero male alla UX.

Essenzialmente bisogno di aggiungere questa riga sull'evento ACTION_DOWN della CNA:

computeScroll(); 

Ecco quello che sto usando:

public class MyNestedScrollView extends NestedScrollView { 
private int slop; 
private float mInitialMotionX; 
private float mInitialMotionY; 

public MyNestedScrollView(Context context) { 
    super(context); 
    init(context); 
} 

private void init(Context context) { 
    ViewConfiguration config = ViewConfiguration.get(context); 
    slop = config.getScaledEdgeSlop(); 
} 

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

public MyNestedScrollView(Context context, AttributeSet attrs, int defStyleAttr) { 
    super(context, attrs, defStyleAttr); 
    init(context); 
} 


private float xDistance, yDistance, lastX, lastY; 

@Override 
public boolean onInterceptTouchEvent(MotionEvent ev) { 
    final float x = ev.getX(); 
    final float y = ev.getY(); 
    switch (ev.getAction()) { 
     case MotionEvent.ACTION_DOWN: 
      xDistance = yDistance = 0f; 
      lastX = ev.getX(); 
      lastY = ev.getY(); 

      // This is very important line that fixes 
      computeScroll(); 


      break; 
     case MotionEvent.ACTION_MOVE: 
      final float curX = ev.getX(); 
      final float curY = ev.getY(); 
      xDistance += Math.abs(curX - lastX); 
      yDistance += Math.abs(curY - lastY); 
      lastX = curX; 
      lastY = curY; 

      if (xDistance > yDistance) { 
       return false; 
      } 
    } 


    return super.onInterceptTouchEvent(ev); 
} 

}

utilizzare questa classe in atto di nestedscrollview nel file xml e gli elenchi secondari dovrebbero intercettare e gestire correttamente gli eventi di tocco.

Phew, in realtà ci sono alcuni bug come questi che mi fanno venir voglia di abbandonare del tutto la libreria di supporto del design e rivisitarla quando è più matura.

+0

Ha funzionato! Grazie! – Sam

1

ho riuscì a fare lo scorrimento orizzontale in un genitore a scorrimento verticale con un ViewPager:

<android.support.v4.widget.NestedScrollView 

    ... 

    <android.support.v4.view.ViewPager 
     android:id="@+id/pager_known_for" 
     android:layout_width="match_parent" 
     android:layout_height="350dp" 
     android:minHeight="350dp" 
     android:paddingLeft="24dp" 
     android:paddingRight="24dp" 
     android:clipToPadding="false"/> 

public class UniversityKnownForPagerAdapter estende PagerAdapter {

public UniversityKnownForPagerAdapter(Context context) { 
    mContext = context; 
    mInflater = LayoutInflater.from(mContext); 
} 

@Override 
public Object instantiateItem(ViewGroup container, int position) { 
    View rootView = mInflater.inflate(R.layout.card_university_demographics, container, false); 

    ... 

    container.addView(rootView); 

    return rootView; 
} 

@Override 
public void destroyItem(ViewGroup container, int position, Object object) { 
    container.removeView((View)object); 
} 

@Override 
public int getCount() { 
    return 4; 
} 

@Override 
public boolean isViewFromObject(View view, Object object) { 
    return (view == object); 
} 

Unico problema: è necessario fornire un'altezza fissa alla visualizzazione del cercapersone

+0

Grazie per la risposta. Ho provato anche tu la tua soluzione e ho fatto in modo che il viewpager funzionasse e scorresse, ma gli stessi problemi di scorrimento che ho menzionato sopra sono accaduti anche qui. Vedi la mia risposta per la correzione. – falc0nit3

+0

Hai provato con un viewpager invece di un recyclerview? –

+0

L'ho fatto, non stava ancora intercettando troppo bene gli eventi. Il problema non è con le implementazioni della lista dei bambini (Recyclerview/Viewpager/HorizontalListView etc), penso, ma piuttosto la libreria NestedScrollView. (come ho menzionato nella mia risposta sopra) – falc0nit3

Problemi correlati