7

I'm going to achieve this UI in my App: UI

Well, Some ways that I tried before:

1. Using CollapsingToolbarLayout I put my CardView insid of CollapsingToolbarLayout and put them all in 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: I removed unrelated codes, don't mention me

This Way works correctly but!!! When CardView height goes taller than screen height, it's content igonered by AppBarLayout and does not show to user

2. Using NestedScrollView I put CardView and RecyclerView inside NestedScrollView. But the problem is When User Reached To end of RecyclerView and then scroll back to top, fling goes laggy and buggy and stop some where ans user have to scroll more and more to get to top!

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

How can fix this issue?! I don't want use adapters that make header for recyclerview, I got performance related issue from some of them.

Answer

Put RecyclerView inside NestedScrollView as you can see in 2 and apply .setNestedScrollingEnabled and set it to false

MAY3AM
  • 1,122
  • 3
  • 15
  • 40
  • 1
    If I ignore performance issue for a while, you want to fix `CardView` on top or simply scroll like other items in `RecyclerView`? – Rehan May 25 '16 at 12:46
  • @Rehan Yep, I want this exactly – MAY3AM May 25 '16 at 12:50
  • I actually asked you which one you actually want. Assuming you want the second one (i.e. `CardView` to scroll like other items in `RecyclerView`) Can you post the second layout in which you put `CardView` and `RecyclerView` inside `NestedScrollView`? – Rehan May 25 '16 at 12:59
  • @Rehan Oops! my bad, Sorry. What i want is this: this is a post activity that cardView hold post related information (like image, description,..) and in recyclerview under it, we are going to shoe related posts. I want when user scroll the recyclerview, cardview scrolled too and goes off of screen – MAY3AM May 25 '16 at 13:05

2 Answers2

10

You should use getItemViewType. It is easy and won't create any performance overhead. Change the code in your Adapter like this:

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


UPDATE 1

If you don't want to update the adapter, you can use

<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 is available in API Level 21 through xml.
For lower APIs use java method i.e. recyclerView.setNestedScrollingEnabled(false); or ViewCompat.setNestedScrollingEnabled(recyclerView, false);

NOTE (12-12-2016)

When using nested scroll. Be aware of the known issue of RecyclerView not recycling views as asked here and here (apparent reason answered by Arpit Ratan and me respectively). So I'll suggest to go with the first solution i.e. using getItemViewType. For more details, see complete and better answers like this or this.


UPDATE 2

You can use setFullSpan. If the orientation of your StaggeredGridLayoutManager is vertical, you can use the following code to span it's width to full screen:

public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
    if (position == 0) {
        StaggeredGridLayoutManager.LayoutParams layoutParams = (StaggeredGridLayoutManager.LayoutParams) viewHolder.itemView.getLayoutParams();
        layoutParams.setFullSpan(true);
    }
}
Community
  • 1
  • 1
Rehan
  • 3,130
  • 4
  • 28
  • 28
  • It seems you forgot `StaggeredLayoutManager`!! for first child as you mention we should force view to fille screen by setting LayoutParams... we test this way before... – MAY3AM May 26 '16 at 04:26
  • @MAY3AM Yes you'll have to set `LayoutParams` to make first view full screen (as I mentioned in *Update 2*). But if you don't want to do it this way, you can still use `NestedScrollView` (as in *Update 1*). It should work for you! – Rehan May 26 '16 at 06:14
  • As I said in my question, we tried both ways. lets talk about `NestedScrollView`, it is reliable, but when user reached to end of recyclerview, and scroll back to top! fling goes buggy and laggy! What's your solution for this? – MAY3AM May 26 '16 at 07:06
  • @MAY3AM Well I haven't personally experience such issue when using `NestedScrollView` with `RecyclerView` so I don't have any solution for it. But yes, the lag can be because of your Adapter, as we know if there is a lot of code in Adapter, it can cause lag while scrolling! – Rehan May 26 '16 at 07:19
  • No it's not adapter performance related! I think it's related to `Behavior` – MAY3AM May 26 '16 at 07:21
  • @MAY3AM Yes, behaviour can be the issue. Try adding `app:layout_behavior="@string/appbar_scrolling_view_behavior"` in `NestedScrollView`, `CardView` and `RecyclerView` as well. May be it can help you. – Rehan May 26 '16 at 07:26
  • @MAY3AM In addition to that, try setting `android:nestedScrollingEnabled` to `true` in `RecyclerView` – Rehan May 26 '16 at 07:31
  • `android:nestedScrollingEnabled` is available in API 21 and higher!! my minimum api is 10! – MAY3AM May 26 '16 at 07:37
  • @MAY3AM Oops. You might need to try something different then. I hope someone else might help you get over this issue. Good Luck :) – Rehan May 26 '16 at 07:41
  • Thank you for your help ;) – MAY3AM May 26 '16 at 07:50
  • 1
    Hey dude, `nestedScrollingEnabled` was answer! i've set this in my code to recyclerview `ViewCompat.setNestedScrollingEnabled(recyclerView, false)`. Post as Answer and I'll accept it. So many thank ;) – MAY3AM May 26 '16 at 08:14
  • @MAY3AM Great. Here you go :) – Rehan May 26 '16 at 08:49
4

the problem in 2.using

But the problem is When User Reached To end of RecyclerView and then scroll back to top

it can be deal by add android:descendantFocusability="blocksDescendants in the first layout under the NestedScrollView like this:

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

it work for me. NestedScrollView scrolls to top on Recyclerview resized

Community
  • 1
  • 1
张小峰
  • 41
  • 1