13

I'm trying to get this working: I basically want two Recyclerviews in one ViewPager. I followed this Tutorial: http://android-java-development.blogspot.de/2012/05/system.html, but it doesn't seem to work. I looks like the view pager is empty and the recycler view doesn't show up.

Here's my layout code:

<android.support.v4.widget.SwipeRefreshLayout
        android:id="@+id/pager_refresh_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingTop="@dimen/tab_height">

        <android.support.v4.view.ViewPager
            android:id="@+id/pager"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@color/accent"/>
    </android.support.v4.widget.SwipeRefreshLayout>

And my PageAdapter:

public class NewsPagerAdapter extends PagerAdapter {
    private Context context;
    private Vector<RecyclerView> recyclerViewList;
    private String[] titles;

    public NewsPagerAdapter(Context context, int titlesId) {
        this.context = context;
        this.recyclerViewList = new Vector<>();

        setTitles(titlesId);
    }

    public void add(RecyclerView recyclerView) {
        recyclerViewList.add(recyclerView);
    }

    public RecyclerView.Adapter getAdapterForViewAtIndex(int index) {
        return recyclerViewList.get(index).getAdapter();
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        container.addView(recyclerViewList.get(position),
                new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 100)
        );
        return container;
    }

    @Override
    public int getCount() {
        return recyclerViewList.size();
    }

    @Override
    public boolean isViewFromObject(View view, Object object) {
        return view.equals(object);
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        container.removeView((View) object);
    }

    @Override
    public CharSequence getPageTitle(int position) {
        return titles[position];
    }

    public void setTitles(int titles) {
        this.titles = context.getResources().getStringArray(titles);
    }
}

And my onCreatView method:

GridLayoutManager layoutManager1 = new GridLayoutManager(getActivity(), getResources().getInteger(R.integer.news_column_count));

GridLayoutManager layoutManager2 = new GridLayoutManager(getActivity(), getResources().getInteger(R.integer.news_column_count));

RecyclerView listView1 = new RecyclerView(getActivity());
RecyclerView listView2 = new RecyclerView(getActivity());
listView1.setLayoutManager(layoutManager1);
listView2.setLayoutManager(layoutManager2);

NewsAdapter adapter1 = new NewsAdapter(getActivity(), null);
NewsAdapter adapter2 = new NewsAdapter(getActivity(), null);
adapter1.setOnItemClickListener(this);
adapter2.setOnItemClickListener(this);

listView1.setAdapter(adapter1);
listView2.setAdapter(adapter2);

newsPagerAdapter.add(listView1);
newsPagerAdapter.add(listView2);

newsViewPager.setAdapter(newsPagerAdapter);

Here I'm passing the cursor object to the adapter:

@Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
        ((NewsAdapter) newsPagerAdapter.getAdapterForViewAtIndex(0)).swapCursor(data);
    }
tobs
  • 699
  • 2
  • 8
  • 24
  • 1
    It seems to me that you missed the layout params for the RecyclerViews that you created programmatically. Try to use something like this `RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, 100);` for both of your views – Zsolt Boldizsar May 11 '15 at 16:07
  • thanks a lot for your reply! Unfortunately, the recycler view still seems to be invisible – tobs May 11 '15 at 16:18
  • ok, look at the adapter implementation – tobs May 11 '15 at 16:24
  • I would do two things but let me first ask you a question. Where are you populating the two RecyclerViews? As I see, you pass null as second parameter in the NewsAdapter (which I assume it is the collection). Am I right? Without having any items to render, RecyclerView will be empty (invisible) – Zsolt Boldizsar May 11 '15 at 16:29
  • Yeah, the adapter is a cursor adapter implementation. I basically start a loader and pass the results back to the adapter (I'll add the code) – tobs May 11 '15 at 16:33
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/77534/discussion-between-zsolt-boldizsar-and-tobs). – Zsolt Boldizsar May 11 '15 at 16:36
  • https://androidbeasts.wordpress.com/2015/08/11/tabs-with-swipe-views/#more-79 – Aakash Aug 11 '15 at 23:17

1 Answers1

14

You have to extend FragmentPagerAdapter or FragmentStatePagerAdapter in order to easily embed RecyclerView. If you are going to update your ViewPager contents during its lifecycle it is strictly recommended to use FragmentStatePagerAdapter

You will have to create additional fragment layout, containing RecyclerView.

If you wish to update your ViewPager with SwipeRefreshLayout, don't wrap it with SwipeRefreshLayout. Instead, you must have SwipeRefreshLayout inside fragment layout.

Therefore for your fragment you may get the following xml:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/listRefresh"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <android.support.v7.widget.RecyclerView
        android:id="@+id/categoryList"
        android:scrollbars="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</android.support.v4.widget.SwipeRefreshLayout>

And create additional Fragment class, which will inflate that layout and implement methods, that you will need to update refresh indicator status.

A bit old example is found here: http://developer.android.com/training/implementing-navigation/lateral.html

If you wish to connect your ViewPager with new support library TabLayout, it is easily one with:

tabLayout.setupWithViewPager(viewPager);

Finally, if you will update your "fragmented" ViewPager, don't try to reset the adapter, as fragments are managed not with adapter, but with FragmentManager. It is wiser to update content of corresponding RecyclerViews

public class MyFragmentedPagerAdapter extends FragmentStatePagerAdapter {
    private final TabLayout mTabLayout;
    private final SwipeRefreshLayout.OnRefreshListener mRefreshListener;
    private Vector<PriceListFragment> fragmentList;
    private Vector<String> titles;

    public MyFragmentedPagerAdapter(FragmentManager fm, MyComplexData data, OnCartActionListener listener, TabLayout tabLayout, SwipeRefreshLayout.OnRefreshListener refreshListener) {
        super(fm);
        mTabLayout = tabLayout;

        // external refresh listener, that will trigger an updateData() 
        mRefreshListener = refreshListener;

        fragmentList = new Vector<>();
        titles = new Vector<>();
        updateData(data);
    }

    public void updateData(MyComplexData data) {
        boolean updateTabs = false;
        boolean hasNewData = false;

        Vector<String> newTitles = new Vector<>();

        int position = 0;
        for(TabContents tabContents : data.getTabContents()) {

            if(tabContents.getListContents() == null)
                continue;
            hasNewData = true;
            boolean isNewFragment;

            MyFragment fragment;
            try {
                fragment = fragmentList.get(position);
                isNewFragment = false;
            } catch (ArrayIndexOutOfBoundsException e) {
                fragment = new MyFragment();
                isNewFragment = true;
            }
            // Update the data, title and hide update indicator of SwipeRefreshLayout
            fragment.setTabContents(tabContents);

            newTitles.add(tabContents.getName());

            if(isNewFragment) {
                fragment.setRefreshListener(mRefreshListener);
                fragmentList.add(fragment);
            }
            position++;
        }

        if(!hasNewData)
            return;

        // we need to decide, whether to update tabs
        if(titles.size() != newTitles.size()) {
            updateTabs = true;
        } else {
            for(position = 0; position < titles.size(); position++) {
                if(!titles.get(position).equals(newTitles.get(position))) {
                    updateTabs = true;
                    break;
                }
            }
        }

        titles = newTitles;
        notifyDataSetChanged();

        if(updateTabs)
            mTabLayout.setTabsFromPagerAdapter(this);
    }

    @Override
    public Fragment getItem(int position) {
        return fragmentList.get(position);
    }

    // You need to override this method as well
    @Override
    public int getItemPosition(Object object) {
        MyFragment fragment = (MyFragment) object;
        String title = (String) fragment.getTitle();
        int position = titles.indexOf(title);

        if (position >= 0) {
            return position;
        } else {
            return POSITION_NONE;
        }
    }

    @Override
    public int getCount() {
        return titles.size();
    }

    @Override
    public CharSequence getPageTitle(int position) {
        return fragmentList.get(position).getTitle();
    }
}

Your MyFragment class has to implement getTitle() method.

Клаус Шварц
  • 3,158
  • 28
  • 44
  • I'll mark this as the answer because thats the same conclusion i came to. I just thought it would be more efficient not to use fragments because I habe the same underlying dataset for all the views. Anyway, thanks for your help. – tobs Jun 18 '15 at 15:12
  • 2
    Thank you. I posted that answer because I couldn't find any answer on that question for other men who will search it including myself in future =) – Клаус Шварц Jun 19 '15 at 15:32
  • I had extends FragmentPagerAdapter and from days trying to find why RecyclerView doesnt update. After reading your reply I have changed extends FragmentStatePagerAdapter and it worked .. Thank YOUU – Emre Kilinc Arslan Jan 18 '18 at 18:42
  • You are welcome. That's incredible how such an old answer can still be useful :) – Клаус Шварц Jan 19 '18 at 08:09