Работа с RecyclerView, NestedScrollView и CardView

Я собираюсь реализовать этот пользовательский интерфейс в своем приложении: UI

Ну, некоторые способы, которые я пробовал раньше:

<сильный>1. Используя CollapsingToolbarLayout, я поместил CardView внутрь CollapsingToolbarLayout и поместил их все в AppBarLAyout.

<android.support.design.widget.CoordinatorLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

        <android.support.design.widget.CollapsingToolbarLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:layout_scrollFlags="scroll|exitUntilCollapsed" >

            <CardView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                />
                  <!-- My Views Goes there -->
            </CardView

            <android.support.v7.widget.Toolbar
                android:id="@+id/flexible.example.toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                android:background="@null"
                app:layout_collapseMode="pin"
                style="@style/ToolBarWithNavigationBack"
                />
        </android.support.design.widget.CollapsingToolbarLayout>

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

    <RecyclerView
        app:layout_behavior="@string/appbar_scrolling_view_behavior"
    ></RecyclerView>

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

P.S. Я удалил несвязанные коды, не упоминайте меня

Этот способ работает правильно, но!!! Когда высота CardView превышает высоту экрана, AppBarLayout игнорирует его содержимое и не показывает его пользователю.

<сильный>2. Используя NestedScrollView, я поместил CardView и RecyclerView внутрь NestedScrollView. Но проблема в том, что когда пользователь доходит до конца RecyclerView, а затем прокручивает вверх, бросок идет с задержками и ошибками и останавливается где-то, где пользователю приходится прокручивать все больше и больше, чтобы добраться до вершины!

<android.support.v4.widget.NestedScrollView
    android:id="@+id/nested_scrollbar"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_gravity="fill_vertical"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    android:scrollbars="none" >
        <LinearLayout
            android:id="@+id/nested_scrollbar_linear"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical" >

                <android.support.v7.widget.CardView
                    android:id="@+id/flexible.example.cardview"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    app:cardBackgroundColor="@color/post_card_backgroind"
                    app:cardCornerRadius="0dp"
                    app:cardElevation="0dp">

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

                <android.support.v7.widget.RecyclerView
                    android:id="@+id/list_view"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginBottom="@dimen/four"
                    android:layout_marginEnd="@dimen/four"
                    android:layout_marginLeft="@dimen/four"
                    android:layout_marginRight="@dimen/four"
                    android:layout_marginStart="@dimen/four"
                    android:layout_marginTop="@dimen/four"
                    app:layout_behavior="@string/appbar_scrolling_view_behavior" />

    </LinearLayout>

</android.support.v4.widget.NestedScrollView>

Как можно решить эту проблему?! Я не хочу использовать адаптеры, которые создают заголовок для recyclerview, у меня возникли проблемы с производительностью от некоторых из них.

Ответить

Поместите RecyclerView внутрь NestedScrollView, как вы можете видеть на 2, примените .setNestedScrollingEnabled и установите его на false


comment
Если я какое-то время проигнорирую проблему с производительностью, вы хотите исправить CardView сверху или просто прокручивать, как другие элементы в RecyclerView?   -  person Rehan    schedule 25.05.2016
comment
@Rehan Да, я хочу именно этого   -  person MAY3AM    schedule 25.05.2016
comment
Я на самом деле спросил вас, какой из них вы на самом деле хотите. Предполагая, что вы хотите, чтобы второй (то есть CardView прокручивался, как и другие элементы в RecyclerView), можете ли вы опубликовать второй макет, в котором вы поместили CardView и RecyclerView внутри NestedScrollView?   -  person Rehan    schedule 25.05.2016
comment
@Rehan Ой! мой плохой, извините. Что я хочу, так это: это активность публикации, в которой cardView содержит информацию, связанную с публикацией (например, изображение, описание и т. д.), и в recyclerview под ней мы собираемся размещать связанные публикации. Я хочу, чтобы когда пользователь прокручивал recyclerview, карточка тоже прокручивалась и исчезала с экрана   -  person MAY3AM    schedule 25.05.2016


Ответы (2)


Вы должны использовать getItemViewType . Это легко и не создаст никаких накладных расходов на производительность. Измените код в своем Adapter следующим образом:

public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    class CardViewHolder extends RecyclerView.ViewHolder {
        ...
    }

    class ItemViewHolder extends RecyclerView.ViewHolder {
        ...
    }

    @Override
    public int getItemViewType(int position) {
        if (position == 0) {
            return 0; // Card Type
        } else {
            return 1; // Item Type
        };
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
         switch (viewType) {
             case 0: 
                 // Card Type
                 return new CardViewHolder(...);
             case 1: 
                 // Item Type
                 return new ItemViewHolder(...);
         }
    }

    // Optional
    // If your data list does not contain CardView data
    // You may need to add extra count in adapter

    @Override
    public final int getItemCount() {
        // Add one count for CardView data
        return list.size() + 1;
    }

    @Override
    public T getItem(int position) {
        // As the position is change because of CardView at position 0
        // So you may have to decrement the corresponding index 
        return list.get(position - 1);
    }
}


ОБНОВЛЕНИЕ 1

Если вы не хотите обновлять адаптер, вы можете использовать

<android.support.v4.widget.NestedScrollView
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <CardView
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
              <!-- Views Goes there -->
        </CardView>
        <android.support.v7.widget.RecyclerView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            // This is the key
            android:nestedScrollingEnabled="false"/>
    </LinearLayout>
</android.support.v4.widget.NestedScrollView>

android:nestedScrollingEnabled доступен в API уровня 21 через XML.
Для более низких API используйте метод java, т. е. recyclerView.setNestedScrollingEnabled(false); или ViewCompat.setNestedScrollingEnabled(recyclerView, false);

ПРИМЕЧАНИЕ (12 декабря 2016 г.)

При использовании вложенной прокрутки. Помните об известной проблеме, связанной с тем, что RecyclerView не перерабатывает представления, как указано здесь и здесь (очевидная причина, на которую ответил Арпит Ратан и меня соответственно). Поэтому я предлагаю использовать первое решение, то есть использовать getItemViewType. Дополнительные сведения см. в полных и лучших ответах, таких как этот или это.


ОБНОВЛЕНИЕ 2

Вы можете использовать setFullSpan. . Если ориентация вашего StaggeredGridLayoutManager вертикальная, вы можете использовать следующий код, чтобы расширить его ширину на весь экран:

public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
    if (position == 0) {
        StaggeredGridLayoutManager.LayoutParams layoutParams = (StaggeredGridLayoutManager.LayoutParams) viewHolder.itemView.getLayoutParams();
        layoutParams.setFullSpan(true);
    }
}
person Rehan    schedule 25.05.2016
comment
Кажется, вы забыли StaggeredLayoutManager!! для первого ребенка, как вы упомянули, мы должны принудительно просмотреть экран заполнения, установив LayoutParams... мы тестировали этот способ раньше... - person MAY3AM; 26.05.2016
comment
@MAY3AM Да, вам нужно установить LayoutParams, чтобы сделать первый просмотр полноэкранным (как я упоминал в Обновлении 2). Но если вы не хотите делать это таким образом, вы все равно можете использовать NestedScrollView (как в Обновлении 1). Это должно работать на вас! - person Rehan; 26.05.2016
comment
Как я сказал в своем вопросе, мы пробовали оба пути. давайте поговорим о NestedScrollView, это надежно, но когда пользователь дошел до конца recyclerview и прокрутил обратно вверх! флинг идет глючит и тормозит! Каково ваше решение для этого? - person MAY3AM; 26.05.2016
comment
@MAY3AM MAY3AM Ну, я лично не сталкивался с такой проблемой при использовании NestedScrollView с RecyclerView, поэтому у меня нет для нее решения. Но да, задержка может быть из-за вашего адаптера, поскольку мы знаем, что если в адаптере много кода, это может вызвать задержку при прокрутке! - person Rehan; 26.05.2016
comment
Нет, это не связано с производительностью адаптера! Я думаю, это связано с Behavior - person MAY3AM; 26.05.2016
comment
@MAY3AM Да, проблема может быть в поведении. Попробуйте также добавить app:layout_behavior="@string/appbar_scrolling_view_behavior" в NestedScrollView, CardView и RecyclerView. Может быть, это может помочь вам. - person Rehan; 26.05.2016
comment
@MAY3AM В дополнение к этому попробуйте установить android:nestedScrollingEnabled на true в RecyclerView - person Rehan; 26.05.2016
comment
android:nestedScrollingEnabled доступен в API 21 и выше!! мой минимальный API 10! - person MAY3AM; 26.05.2016
comment
@MAY3AM Упс. Возможно, тогда вам придется попробовать что-то другое. Я надеюсь, что кто-то еще может помочь вам справиться с этой проблемой. Удачи :) - person Rehan; 26.05.2016
comment
Эй, чувак, nestedScrollingEnabled был ответ! я установил это в своем коде на recyclerview ViewCompat.setNestedScrollingEnabled(recyclerView, false). Отправьте как ответ, и я приму это. Большое спасибо ;) - person MAY3AM; 26.05.2016
comment
@MAY3AM Отлично. Ну вот :) - person Rehan; 26.05.2016

проблема в 2.использовании

Но проблема в том, что когда пользователь достиг конца RecyclerView, а затем прокрутил вверх

это можно сделать, добавив android:descendantFocusability="blocksDescendants в первый макет под NestedScrollView следующим образом:

<android.support.v4.widget.NestedScrollView
android:id="@+id/nested_scrollbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="fill_vertical"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
android:scrollbars="none" >
    <LinearLayout
        android:id="@+id/nested_scrollbar_linear"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:descendantFocusability="blocksDescendants" >

это работает для меня. NestedScrollView прокручивается вверх при изменении размера Recyclerview

person 张小峰    schedule 02.05.2017