35

Это приложение, которое я пытаюсь построить со всеми элементами, отображенных ниже:Android Layout: горизонтальный Recyclerview внутри вертикальной Recyclerview внутри ViewPager с спиральными поведений

Veggies app

Все работает, однако, Я хочу, чтобы внутренний горизонтальный recyclerview не захватывал ни один из вертикальных свитков. Все вертикальные свитки должны идти в направлении внешнего вертикального рециркуляции, а не горизонтального, чтобы вертикальная прокрутка позволяла панели инструментов выйти из вида в соответствии с ее scrollFlag.

Когда я кладу палец на части «Клубничный завод» в recyclerview и выполните прокрутку вверх, то выделите из панели инструментов:

strawberry plant

Если я кладу палец на горизонтальной Scrollview и выполните прокрутку вверх , он вообще не прокручивает панель инструментов.

Ниже приведен мой код макета xml.

активность макет XML:

<?xml version="1.0" encoding="utf-8"?> 
<FrameLayout 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:app="http://schemas.android.com/apk/res-auto" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:id="@+id/fragment_container" 
    android:clipChildren="false"> 

    <android.support.design.widget.CoordinatorLayout 
     android:orientation="vertical" 
     android:layout_width="match_parent" 
     android:layout_height="match_parent" 
     android:id="@+id/container" 
     > 

    <android.support.design.widget.AppBarLayout 
     android:id="@+id/appBarLayout" 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content"> 

     <android.support.v7.widget.Toolbar 
      android:id="@+id/toolbar" 
      android:minHeight="?attr/actionBarSize" 
      android:background="?attr/colorPrimary" 
      android:layout_width="match_parent" 
      android:layout_height="wrap_content" 
      app:layout_scrollFlags="scroll|enterAlways"> 

     </android.support.v7.widget.Toolbar> 

     <android.support.design.widget.TabLayout 
      android:id="@+id/sliding_tabs" 
      android:layout_width="match_parent" 
      android:layout_height="wrap_content" 
      android:background="?attr/colorPrimary" 
      style="@style/CustomTabLayout" 
      /> 

    </android.support.design.widget.AppBarLayout> 
    <android.support.v4.view.ViewPager 
     android:id="@+id/viewPager" 
     android:layout_width="match_parent" 
     android:layout_height="match_parent" 
     app:layout_behavior="@string/appbar_scrolling_view_behavior" 
     /> 

    </android.support.design.widget.CoordinatorLayout> 

</FrameLayout> 

«Фрукты» фрагмент XML макет (который является код фрагмента - фрагмент обозначен на рисунке выше):

<?xml version="1.0" encoding="utf-8"?> 
<RelativeLayout 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    android:orientation="vertical" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent"> 

    <ProgressBar 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:id="@+id/progressBar" 
     android:visibility="gone" 
     android:layout_centerInParent="true" 
     android:indeterminate="true"/> 

<!-- <android.support.v7.widget.RecyclerView--> 
    <com.example.simon.customshapes.VerticallyScrollRecyclerView 
     android:id="@+id/main_recyclerview" 
     android:layout_width="match_parent" 
     android:layout_height="match_parent" 
     /> 

</RelativeLayout> 

Я использовал собственный класс VerticallyScrollRecyclerView, который следует примеру Google для обработки событий касания в группе просмотра. Его цель состоит в том, чтобы перехватить и истреби все вертикальные события прокрутки, так что он будет прокручиваться в/из панели инструментов: http://developer.android.com/training/gestures/viewgroup.html

Код для VerticallyScrollRecyclerView ниже:

public class VerticallyScrollRecyclerView extends RecyclerView { 

    public VerticallyScrollRecyclerView(Context context) { 
     super(context); 
    } 

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

    public VerticallyScrollRecyclerView(Context context, AttributeSet attrs, int defStyle) { 
     super(context, attrs, defStyle); 
    } 

    ViewConfiguration vc = ViewConfiguration.get(this.getContext()); 
    private int mTouchSlop = vc.getScaledTouchSlop(); 
    private boolean mIsScrolling; 
    private float startY; 

    @Override 
    public boolean onInterceptTouchEvent(MotionEvent ev) { 
     final int action = MotionEventCompat.getActionMasked(ev); 
     // Always handle the case of the touch gesture being complete. 
     if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) { 
      // Release the scroll. 
      mIsScrolling = false; 
      startY = ev.getY(); 
      return super.onInterceptTouchEvent(ev); // Do not intercept touch event, let the child handle it 
     } 
     switch (action) { 
      case MotionEvent.ACTION_MOVE: { 
       Log.e("VRecView", "its moving"); 
       if (mIsScrolling) { 
        // We're currently scrolling, so yes, intercept the 
        // touch event! 
        return true; 
       } 
       // If the user has dragged her finger horizontally more than 
       // the touch slop, start the scroll 
       // left as an exercise for the reader 
       final float yDiff = calculateDistanceY(ev.getY()); 
       Log.e("yDiff ", ""+yDiff); 
       // Touch slop should be calculated using ViewConfiguration 
       // constants. 
       if (Math.abs(yDiff) > 5) { 
        // Start scrolling! 
        Log.e("Scroll", "we are scrolling vertically"); 
        mIsScrolling = true; 
        return true; 
       } 
       break; 
      } 
     } 
     return super.onInterceptTouchEvent(ev); 
    } 


    private float calculateDistanceY(float endY) { 
     return startY - endY; 
    } 

} 

«Фаворит» раскладку который является recyclerview в вертикальной recyclerview:

<?xml version="1.0" encoding="utf-8"?> 

<RelativeLayout 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    android:background="@color/white" 
    xmlns:app="http://schemas.android.com/apk/res-auto"> 

    <TextView 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:text="Favourite" 
     android:layout_marginTop="8dp" 
     android:layout_marginBottom="8dp" 
     android:layout_marginLeft="16dp" 
     android:id="@+id/header_fav"/> 

    <android.support.v7.widget.RecyclerView 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:orientation="horizontal" 
     android:layout_below="@+id/header_fav" 
     android:id="@+id/recyclerview_fav"> 
    </android.support.v7.widget.RecyclerView> 

</RelativeLayout> 

Это было подслушивания меня на некоторое время теперь и я п ot удалось найти решение. кто-нибудь знает, как решить эту проблему?

5 баллов для Гриффинора за правильный ответ и, конечно же, очки репутации на SO.

ответ

85

проверенное решение:

Все, что вам нужно, это позвонить mInnerRecycler.setNestedScrollingEnabled(false); на ваш внутренний RecyclerView s


Объяснение:

RecyclerView имеет поддержку вложенной прокруткой, введенной в API 21 путем реализации интерфейс NestedScrollingChild.Это ценная функция, когда у вас есть прокручиваемый вид внутри другого, который прокручивается в одном направлении, и вы хотите прокручивать внутренний View только при фокусировке.

В любом случае RecyclerView по умолчанию вызывает RecyclerView.setNestedScrollingEnabled(true); на себя при инициализации. Теперь вернемся к проблеме, так как оба из ваших RecyclerView s находятся в пределах одного ViewPager, у которого есть AppBarBehavior, CoordinateLayout должен решить, какой свиток прокрутить, когда вы прокрутите свой внутренний номер RecyclerView; когда включена встроенная прокрутка вашего внутреннего RecyclerView, она получает фокус прокрутки, а CoordinateLayout будет выбирать, чтобы откликнуться на ее прокрутку по внешней прокрутке RecyclerView. Дело в том, что, поскольку ваши внутренние RecyclerView s не прокручиваются по вертикали, нет вертикального изменения прокрутки (с точки зрения CoordinateLayout), и если изменений нет, то AppBarLayout тоже не изменится.

В вашем случае, потому что ваш внутренний RecyclerView s прокручивает в другом направлении, вы можете вывести его из строя, тем самого вызывая CoordinateLayout игнорировать его скроллинг и реагировать на внешней прокрутку RecyclerView «ы.


Примечание:

XML-атрибут android:nestedScrollingEnabled="boolean" не предназначен для использования с RecyclerView, и попытка использовать android:nestedScrollingEnabled="false" приведет к java.lang.NullPointerException так, по крайней мере, на данный момент, вы будете должны сделать это в коде.

+1

Если вы используете привязки данных, хотя, вы можете сделать приложение: nestedScrollingEnabled = "@ {true}", и сойти с рук, не делая этого в коде: D – brAzzi64

+0

@ Спасибо за ваше объяснение. Я пытаюсь использовать setNestedScrollingEnabled (false) для решения аналогичной проблемы, но у меня минимальный уровень API 15. Я использую последнюю библиотеку поддержки. Поддерживается ли это только в API 21 и выше? – user2095470

+0

вы сохранили мой день =) –

2

Протестированный раствор, используйте обычай NestedScrollView().

Код:

public class CustomNestedScrollView extends NestedScrollView { 
    public CustomNestedScrollView(Context context, AttributeSet attrs) { 
     super(context, attrs); 
    } 

    @Override 
    public boolean onInterceptTouchEvent(MotionEvent ev) { 
     if (ev.getAction() == MotionEvent.ACTION_DOWN) { 
     // Explicitly call computeScroll() to make the Scroller compute itself 
      computeScroll(); 
     } 
     return super.onInterceptTouchEvent(ev); 
    } 
} 
2

Я немного поздно, но это будет defintly работать для других, стоящих перед той же проблемой

mRecyclerView.addOnItemTouchListener(new RecyclerView.OnItemTouchListener() { 
      @Override 
      public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) { 
       int action = e.getAction(); 
       // Toast.makeText(getActivity(),"HERE",Toast.LENGTH_SHORT).show(); 
       switch (action) { 
        case MotionEvent.ACTION_POINTER_UP: 
         rv.getParent().requestDisallowInterceptTouchEvent(true); 

         break; 
       } 
       return false; 
      } 
Смежные вопросы