10

Mam pojedynczy, pionowy, zagnieżdżony widok, który zawiera garść widoków recyklingu z konfiguracją poziomego menedżera układu. Pomysł jest podobny do tego, jak wygląda nowy sklep Google Play. Mogę sprawić, by był funkcjonalny, ale nie jest w ogóle gładki. Oto problemy:NestedScrollView i Horizontal RecyclerView Smooth Scrolling

1) Pozioma pozycja recyklingu nie przechwytuje zdarzenia dotykowego przez większość czasu, mimo że dotknęłem go prawym przyciskiem. Widok przewijania wydaje się mieć pierwszeństwo dla większości ruchów. Ciężko jest mi zahaczyć o ruch poziomy. Ten UX jest frustrujący, ponieważ muszę go wypróbować kilka razy, zanim zadziała. Jeśli sprawdzisz sklep z zabawkami, będzie on w stanie przechwycić zdarzenie dotykowe naprawdę dobrze i po prostu działa dobrze. Zauważyłem, że w sklepie z zabawkami sposób, w jaki go ustawili, to wiele poziomych recyrkulacji w jednym pionowym widoku recyklingu. Bez przewijania.

2) Wysokość poziomych widoków recyklerów musi być ustawiona ręcznie i nie ma łatwego sposobu obliczania wysokości elementów podrzędnych.

Oto układ Używam:

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

Ten wzór UI jest bardzo podstawowe i najczęściej używane w wielu różnych aplikacjach. Czytałem wiele SO, w których ppl mówi, że nie jest dobrym pomysłem umieszczenie listy na liście, ale jest to bardzo powszechny i ​​nowoczesny wzór UI używany wszędzie. Pomyśl o interfejsie podobnym do netflix z szeregiem poziomych list przewijania wewnątrz pionowa lista. Czy nie ma na to sprawnego sposobu?

przykład obraz ze sklepu:

Google Play Store

+0

Dziwne jest to, że mam przeciwny problem: chcę, aby NestedScrollView pozwalał na przewijanie w pionie, ale poziomy widok RecyclerView przejmuje zdarzenia dotykowe, więc gdy zaczynam przewijanie w pionie, to na to nie pozwala. Ponadto, btw, jeśli masz tylko kilka elementów do pokazania, możesz użyć prostego HorizontalScrollView z LinearLayout. –

Odpowiedz

13

W związku z tym problem z płynnym przewijaniem jest teraz ustawiony. Został spowodowany przez błąd w NestedScrollView w bibliotece Support Design Library (obecnie 23.1.1).

Możesz przeczytać o problemie i prosty fix tutaj: https://code.google.com/p/android/issues/detail?id=194398

w skrócie, po przeprowadzono romans The nestedscrollview nie zarejestrować kompletny na części scroller i dlatego potrzebny jest dodatkowy " ACTION_DOWN "zdarzenie, aby zwolnić macierzysty widok zagnieżdżony z przechwytywania (zjedzenia w górę) kolejnych zdarzeń. Tak więc, jeśli spróbujesz przewinąć listę swoich dzieci (lub podglądu), po rzuceniu, pierwsze dotknięcie zwalnia rodzicielskie powiązanie NSV, a kolejne dotknięcia będą działały. To czyniło UX naprawdę złym.

Zasadniczo trzeba dodać tę linię na razie ACTION_DOWN z NSV:

computeScroll(); 

Oto co używam:

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

}

użyć tej klasy w miejscu twojego zagnieżdżonego podglądu w pliku xml, a listy potomne powinny przechwytywać i odpowiednio obsługiwać zdarzenia dotykowe.

Uff, w rzeczywistości istnieje kilka takich błędów, które sprawiają, że chcę całkowicie zrezygnować z biblioteki wsparcia projektu i ponownie ją przejrzeć, gdy jest bardziej dojrzała.

+0

Zadziałało! Dzięki! – Sam

1

ja succeded w ten poziome przesuwanie w pionie przewijania macierzystej z 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"/> 

klasy publicznej UniversityKnownForPagerAdapter rozciąga 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); 
} 

Jedyny problem: należy ustawić stałą wysokość do pagera widoku

+0

Dzięki za odpowiedź. Próbowałem też twojego rozwiązania i sprawiłem, że podgląd był gotowy do pracy i przewijania, ale pojawiły się też te same problemy z przewijaniem, o których wspomniałem powyżej. Zobacz moją odpowiedź na poprawkę. – falc0nit3

+0

Czy próbowałeś z podglądem zamiast widoku z recyklingu? –

+0

Zrobiłem, to nadal nie przechwytywało wydarzeń zbyt dobrze. Problem nie dotyczy implementacji list podrzędnych (Recyclerview/Viewpager/HorizontalListView itp.), Ale raczej biblioteki NestedScrollView. (jak wspomniałem w powyższej odpowiedzi) – falc0nit3