user47376
user47376

Reputation: 2273

Android: make Recyclerview behave like LinearLayout

I have a layout such:

<LinearLayout>
   <TextView/>
   <LinearLayout> <-- needs to be a dynamic list
      <JohnDoeView/>
      <JohnDoeView/>
   </LinearLayout>
   <TextView/>
   <LinearLayout> <-- needs to be a another dynamic list
      <JohnDoeView/>
      <JohnDoeView/>
      <JohnDoeView/>
   </LinearLayout>
</LinearLayout>

this results in the image below, and i can scroll the WHOLE layout together.

But when i try to replace those LinearLayout's with RecyclerView's I get TWO separate scroll areas , like two fixed boxes that scroll independently.

<LinearLayout>
   <TextView/>
   <RecyclerView/>
   <TextView/>
   <RecyclerView/>
</LinearLayout>

How can I get the same effect as LinearLayout but with having Dynamic content ??

How I want the layout to look

Upvotes: 3

Views: 3448

Answers (4)

WindRider
WindRider

Reputation: 12318

You don't need to nest RecyclerViews or ListViews or any other scrolling views. You need only the external view to be RecyclerView. The inner lists can be managed via very simple ListLayout class with an adapter for each sub-list.

public class ListLayout extends LinearLayout {
    private Adapter mAdapter;
    private Observer mObserver = new Observer();

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

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

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

    public Adapter getAdapter()
    {
        return mAdapter;
    }

    public void setAdapter(Adapter adapter) {
        if (mAdapter != null)
            mAdapter.unregisterDataSetObserver(mObserver);

        mAdapter = adapter;
        adapter.registerDataSetObserver(mObserver);
        mObserver.onChanged();
    }

    private class Observer extends DataSetObserver {

        @Override
        public void onChanged() {
            final List<View> oldViews = new ArrayList<View>(getChildCount());

            for (int i = 0; i < getChildCount(); i++)
                oldViews.add(getChildAt(i));

            final Iterator<View> iter = oldViews.iterator();

            removeAllViews();

            for (int i = 0; i < mAdapter.getCount(); i++) {
                View convertView = iter.hasNext() ? iter.next() : null;
                View newView = mAdapter.getView(i, convertView, ListLayout.this);
                addView(newView);
            }
            super.onChanged();
        }

        @Override
        public void onInvalidated() {
            removeAllViews();
            super.onInvalidated();
        }
    }
}

https://gist.github.com/sevar83/0e27c26142f2fba97d57

Upvotes: 0

Rohit Jagtap
Rohit Jagtap

Reputation: 1670

Try using this layout structure,

<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:orientation="vertical">

<LinearLayout
    android:layout_height="match_parent"
    android:layout_width="match_parent"
    android:layout_weight="1"
    android:orientation="vertical">
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
    <RecyclerView
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

<LinearLayout
    android:layout_height="match_parent"
    android:layout_width="match_parent"
    android:layout_weight="1"
    android:orientation="vertical">
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
    <RecyclerView
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

Upvotes: 0

Philippe Banwarth
Philippe Banwarth

Reputation: 17755

LinearLayout can handle dynamic changes. It can even animate them, if you use the android:animateLayoutChanges attribute. ListView or Recycler are interesting when the number of items is large (i.e. much more than what the screen can display), to avoid to have a lot of invisible views.

If you really want to use a RecyclerView you could use only one, with multiple view types, e.g. one for TextView, one for the JohnDoeView

Upvotes: 0

natario
natario

Reputation: 25194

I see two solutions.

  1. Insert the whole layout inside a ScrollView.
  2. Use a single RecyclerView.

Solution 1

For this you need to make the RecyclerView wrap its content. Sadly, you can't just put android:layout_height="wrap_content" because RecyclerView does not support that. Luckily there are custom solutions for that. I've been using it and it works well.

For instance, there's this custom LinearLayoutManager which you could assign to both the RecyclerViews. Just follow the instructions in the page I linked.

Solution 2

You could use a single RecyclerView. This might require harder work because you have to:

  • merge your adapter into a single one;
  • assign to a certain position your divider (TextView, Switch or whatever).

This is surely possible, just take a look at one of the (many) examples out there on RecyclerView with multiple child types.

Upvotes: 3

Related Questions