10

Ich habe eine einzelne vertikale NestedScrollview, die eine Reihe von Recyclerview mit einem horizontalen Layoutmanager Setup enthält. Die Idee ist ähnlich wie beim neuen Google Play Store. Ich kann es funktionell machen, aber es ist überhaupt nicht glatt. Hier sind die Probleme:NestedScrollView und Horizontal RecyclerView Smooth Scrolling

1) Der horizontale Recyclerview-Artikel kann das Touch-Ereignis meistens nicht abfangen, obwohl ich direkt darauf klopfe. Die Bildlaufansicht scheint bei den meisten Bewegungen Vorrang zu haben. Es ist schwer für mich, einen Haken in die horizontale Bewegung zu bekommen. Dieses UX ist frustrierend, da ich es einige Male versuchen muss, bevor es funktioniert. Wenn Sie den Play Store überprüfen, ist es in der Lage, das Touch-Event wirklich gut abzufangen und es funktioniert einfach gut. Ich bemerkte im Play Store, wie sie es einrichten, ist viele horizontale Recyclerviews in einem vertikalen Recyclerview. Kein scrollview.

2) Die Höhe der horizontalen RecyclerViews muss manuell festgelegt werden und es gibt keine einfache Möglichkeit, die Höhe der Kinderelemente zu berechnen.

Hier ist das Layout Ich verwende:

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

Dieses UI-Muster ist sehr einfach und sehr wahrscheinlich in vielen verschiedenen Anwendungen eingesetzt. Ich habe viele SO's gelesen, wo ppl sagen, dass es eine schlechte Idee ist, eine Liste innerhalb einer Liste zu setzen, aber es ist ein sehr häufiges und modernes UI-Muster, das überall verwendet wird. Denken Sie an Netflix-ähnliche Schnittstelle mit einer Reihe von horizontalen Scroll-Listen eine vertikale Liste. Gibt es dafür keinen reibungslosen Weg?

Beispielbild aus dem Speicher:

Google Play Store

+0

Seltsame Sache ist, dass ich das umgekehrte Problem habe: Ich möchte die NestedScrollView, um vertikal zu scrollen, aber die horizontale RecyclerView nimmt die Berührungsereignisse so, wenn ich das vertikale Scrollen darauf starten, erlaubt es nicht. Auch, wenn Sie nur ein paar Elemente haben, können Sie eine einfache HorizontalScrollView mit LinearLayout verwenden. –

Antwort

13

Damit ist das problemlose Scrollen jetzt behoben. Es wurde durch einen Fehler in der NestedScrollView in der Design Support Library (derzeit 23.1.1) verursacht.

Sie können über das Thema gelesen und die einfache Lösung hier: https://code.google.com/p/android/issues/detail?id=194398

Kurz, nachdem Sie einen Seitensprung ausgeführt, hat der nestedscrollview keine vollständige auf dem Stellrad Komponente registrieren und so brauchte es eine zusätzliche " ACTION_DOWN 'Ereignis, um die übergeordnete NestedScrollview davon abzuhalten, die nachfolgenden Ereignisse abzufangen (zu verschlingen). Also, was passiert ist, wenn Sie versucht haben, Ihre Kinderliste (oder Viewpager) zu scrollen, nach einem Fling, gibt die erste Berührung die Eltern-NSV-Bindung frei und die nachfolgenden Berührungen würden funktionieren. Das machte die UX wirklich schlecht.

Im Wesentlichen diese Zeile auf dem ACTION_DOWN Ereignis des NSV hinzufügen müssen:

computeScroll(); 

Hier ist, was ich verwende:

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

}

Verwenden Sie diese Klasse an Ort und Stelle Ihrer NestedScrollview in der XML-Datei, und die Child-Listen sollten die Touch-Ereignisse richtig abfangen und behandeln.

Puh, es gibt eigentlich ein paar Bugs wie diese, die mich dazu bringen wollen, die Design-Support-Bibliothek insgesamt zu verlassen und sie wieder zu besuchen, wenn sie ausgereifter ist.

+0

Es hat funktioniert! Vielen Dank! – Sam

1

Ich habe dabei das horizontale Scrollen in einem vertikal scrollen Elternteil mit einem ViewPager succeded:

<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 PagerAdapter erstreckt {

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

Nur Problem: Sie müssen dem Ansichtspager eine feste Höhe zuweisen

+0

Danke für Ihre Antwort. Ich habe deine Lösung auch versucht und den Viewpager zum Arbeiten und Scrollen gebracht, aber die gleichen Scroll-Probleme, die ich oben erwähnt habe, sind auch hier passiert. Siehe meine Antwort für die Lösung. – falc0nit3

+0

Haben Sie es mit einem Viewpager anstatt mit einem Recyclerview versucht? –

+0

Ich tat, es war immer noch nicht die Ereignisse zu gut abfangen. Das Problem ist nicht mit den Child-List-Implementierungen (Recyclerview/Viewpager/HorizontalListView etc) ich denke, aber eher die NestedScrollView-Bibliothek. (wie ich in meiner Antwort oben erwähnt habe) – falc0nit3