23

I want to make a 'Photo details' activity or fragment where i display the photo on top and below it aViewpPager that display both comments and likes of the related photo(2 tabs). In order to make the screen 'Scrollable' so i can scroll up/down on both comments and likes and slide left/right i decided to use a RecyclerView with 2 rows :

ROW 1 : The photo (ImageView).

ROW 2 : SlidingTabLayout + ViewPager + FragmentPagerAdapter.

The code compile and run, display the image and the slidingTabLayout but not the ViewPager.

So my two main questions are :

1-What's wrong with my implementation.

2-Is there an alternative or better solution for what i want to achieve ?

Note : I don't want to use a listView with header.I want to use RecyclerView because it's easier to add elements on top/bottom from network.

PhotoDetailsActivity.java

public class MainActivity extends ActionBarActivity {
    RecyclerView recyclerViewPhotoDetails;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        this.recyclerViewPhotoDetails = (RecyclerView) this.findViewById(R.id.recycler_view_photo_details);
        this.recyclerViewPhotoDetails.setLayoutManager(new LinearLayoutManager(this));
        this.recyclerViewPhotoDetails.setAdapter(new PhotoDetailsRecyclerAdapter(this.getSupportFragmentManager()));
    }
}

PhotosDetailsRecyclerAdapter.java

public class PhotoDetailsRecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    private static final int ROW_IMAGE = 0;
    private static final int ROW_LIKES_AND_COMMENTS = 1;
    private static final int TOTAL_ROWS = 2;

    private FragmentManager fragmentManager;

    public PhotoDetailsRecyclerAdapter(FragmentManager fragmentManager) {
        this.fragmentManager = fragmentManager;
    }

    @Override
    public int getItemViewType(int position) {
        if (position == 0) {
            return ROW_IMAGE;
        } else {
            return ROW_LIKES_AND_COMMENTS;
        }
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if(viewType == ROW_IMAGE) {
            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_image, parent, false);
            return new ImageViewHolder(view);
        } else {
            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_comments_and_likes, parent, false);
            return new CommentsAndLikesViewHolder(view);
        }
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int i) {
    }

    @Override
    public int getItemCount() {
        return TOTAL_ROWS;
    }

    public class ImageViewHolder extends RecyclerView.ViewHolder {
        public ImageViewHolder(View itemView) {
            super(itemView);
        }
    }

    public class CommentsAndLikesViewHolder extends RecyclerView.ViewHolder {
        private SlidingTabLayout slidingTabLayout;
        private ViewPager viewPager;

        public CommentsAndLikesViewHolder(View view) {
            super(view);

            slidingTabLayout = (SlidingTabLayout) view.findViewById(R.id.sliding_tab_layout_comments_and_likes);
            viewPager = (ViewPager) view.findViewById(R.id.view_pager_comments_and_likes);

            viewPager.setAdapter(new CommentsAndLikesPagerAdapter(fragmentManager));
            slidingTabLayout.setDistributeEvenly(true);
            slidingTabLayout.setViewPager(viewPager);
        }
    }
}

activity_main.xml

<android.support.v7.widget.RecyclerView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/recycler_view_photo_details"
    android:scrollbars="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    />

layout_image.xml

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

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:adjustViewBounds="true"
        android:scaleType="centerCrop"
        android:src="@drawable/img"
        />

</FrameLayout>

layout_comments_and_likes.xml

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

    <org.bitbucket.androidapp.SlidingTabLayout
        android:id="@+id/sliding_tab_layout_comments_and_likes"
        android:layout_width="match_parent"
        android:layout_height="48dp"
        android:background="@android:color/darker_gray"
        />

    <android.support.v4.view.ViewPager
        android:id="@+id/view_pager_comments_and_likes"
        android:layout_height="match_parent"
        android:layout_width="match_parent"
        android:background="@android:color/holo_blue_dark"
        />

</LinearLayout>

CommentsAndLikesPagerAdapter.java

public class CommentsAndLikesPagerAdapter extends FragmentPagerAdapter {
    private static final int TOTAL_TABS = 2;

    private String[] tabs = { "comments", "likes" };

    public CommentsAndLikesPagerAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public Fragment getItem(int position) {
        if(position == 0) {
            return new CommentsFragment();
        } else {
            return new LikesFragment();
        }
    }

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

    @Override
    public int getCount() {
        return TOTAL_TABS;
    }
}

CommentsFragment.java

 public class CommentsFragment extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_comments, container, false);
        RecyclerView recyclerViewComments = (RecyclerView) view.findViewById(R.id.recycler_view_comments);
        recyclerViewComments.setLayoutManager(new LinearLayoutManager(this.getActivity()));
        recyclerViewComments.setAdapter(new CommentsRecyclerAdapter());
        return view;
    }
}

fragment_comments.xml

<android.support.v7.widget.RecyclerView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/recycler_view_comments"
    android:scrollbars="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    />

LikesFragment.java

public class LikesFragment extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_likes, container, false);
        RecyclerView recyclerViewLikes = (RecyclerView) view.findViewById(R.id.recycler_view_likes);
        recyclerViewLikes.setLayoutManager(new LinearLayoutManager(this.getActivity()));
        recyclerViewLikes.setAdapter(new LikesRecyclerAdapter());
        return view;
    }
}

fragment_likes.xml

<android.support.v7.widget.RecyclerView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/recycler_view_likes"
    android:scrollbars="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    />

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

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="Comment"
        />

</RelativeLayout>

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

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="Like"
        />

</RelativeLayout>
beresfordt
  • 5,088
  • 10
  • 35
  • 43
Brahim Boulkriat
  • 984
  • 2
  • 9
  • 21
  • Using RecyclerView for 2 rows seems like an overkill, why don't you just put that in a LinearLayout in a ScrollView? – Gyome Mar 19 '15 at 21:11
  • @Crumble I tried it but it didn't scroll.This is why i used RecyclerView. – Brahim Boulkriat Mar 19 '15 at 21:13
  • Well, a scrollView is meant to scroll, there must have been something wrong in your implémentation. Recyclerview is really meant for long list that reuses the same views multiple tome, not your case at all. Considere retrying the scrollView for a cleaner, lighter and more optimized code. – Gyome Mar 19 '15 at 21:24
  • Can you also post your CommentsRecyclerAdapter and LikesRecyclerAdapter code? I assume they have at least 1 element. – random Apr 09 '15 at 09:41
  • hi how to design view with scrollable viewpager and recycler card view along with search bar when user scroll down collapse the viewpager images and changes to toolbar looks like google play store app please help me along with navigation drawer – Harsha Feb 09 '16 at 09:09

9 Answers9

47

I've faced this problem and resolved this by set ID for each ViewPager :) ViewPager does not allow sharing of the id in the same fragment, even if it is part of a recyclerview context.

pagerHolder.pager.setId(position);
Jackson Chengalai
  • 3,907
  • 1
  • 24
  • 39
Linh Nguyen
  • 1,264
  • 1
  • 10
  • 22
17

Update the ViewPager height, the recyclerView's items needs a specific height

<android.support.v4.view.ViewPager
    android:id="@+id/view_pager"
    android:layout_height="300dp"
    android:layout_width="match_parent"
    android:background="@android:color/holo_blue_dark" />
daduck
  • 276
  • 3
  • 6
  • 2
    To anyone who may have items of different sizes and therefore needs dynamic pager height, see [this answer](http://stackoverflow.com/a/20784791/1815052). Allows you to use `wrap_content`. Worked for me. – SqueezyMo Jun 03 '16 at 10:57
3

You can look this code and update your code. I used this code my project and worked. You must set ViewPagerAdapter to viewpager inside onBinViewHolder method. If it does not worked, i want to help.

RecylerviewAdapter

    // Replace the contents of a view (invoked by the layout manager)
   @Override
   public void onBindViewHolder(ViewHolder holder, int position) {
      // - get element from your dataset at this position
      // - replace the contents of the view with that element
      initializeViews("Mustafa", holder, position);
   }

   private void initializeViews(final String object, final ViewHolder holder, int position) {
      holder.textViewCount.setText("5");
      holder.imageViewStar.setImageResource(R.drawable.info);
      holder.imageViewFavorite.setImageResource(R.drawable.info);
      ViewPagerBoundariesAdapter adapter = new ViewPagerBoundariesAdapter(activity, new ArrayList<ViewPagerItem>(), listener);
      holder.viewPager.setAdapter(adapter);
      holder.viewPager.setClipToPadding(false);
      holder.viewPager.setPadding(40, 0, 40, 0);
   }

ViewPagerAdapter

/**
 * Created by MustafaS on 10.3.2015.
 */
public class ViewPagerBoundariesAdapter extends PagerAdapter {
   private ArrayList<ViewPagerItem>    pagerItems;
   private LayoutInflater              inflater;
   private Context                     context;
   private ViewPagerItemClickInterface listener;

   public ViewPagerBoundariesAdapter(Context context, ArrayList<ViewPagerItem> pagerItems, ViewPagerItemClickInterface callback) {
      super();
      this.pagerItems = pagerItems;
      this.context = context;
      this.listener = callback;
      inflater = LayoutInflater.from(context);
   }

   @Override
   public Object instantiateItem(ViewGroup container, int position) {

      LinearLayout layout = (LinearLayout) inflater.inflate(R.layout.row_viewpager, container, false);
      ImageView imageViewCampaign = (ImageView) layout.findViewById(R.id.imageview_campaign);
      TextView textViewCampaign = (TextView) layout.findViewById(R.id.textview_campaign);
      imageViewCampaign.setOnClickListener(new View.OnClickListener() {
         @Override
         public void onClick(View v) {
            listener.onViewPagerItemClick(1);
         }
      });
      // textViewCampaign.setText("Lorem ipsum dolor sit amet\n" + "aliquam nec nisi in lorem");
      imageViewCampaign.setImageDrawable(context.getResources().getDrawable(R.drawable.nusret));
      container.addView(layout);
      return layout;
   }

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

   @Override
   public int getCount() {
      return 5;
   }

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

}

recylerview xml

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

recylerview row xml

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

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="8dp"
        android:layout_marginLeft="8dp"
        android:orientation="horizontal">

        <ImageView
            android:id="@+id/imageview_favorite"
            android:layout_width="32dp"
            android:layout_height="32dp"
            android:layout_gravity="center" />

        <TextView
            android:id="@+id/textview_brand_name"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:gravity="center_vertical"
            android:paddingLeft="8dp"
            android:text="Gucci"
            android:textSize="@dimen/standart_text_size" />

        <FrameLayout
            android:layout_width="32dp"
            android:layout_height="32dp"
            android:layout_marginRight="8dp">

            <ImageView
                android:id="@+id/imageview_star"
                android:layout_width="match_parent"
                android:layout_height="match_parent" />

            <TextView
                android:id="@+id/textview_count"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:ellipsize="end"
                android:gravity="center"
                android:singleLine="true"
                android:textSize="@dimen/standart_text_size" />
        </FrameLayout>
    </LinearLayout>

    <android.support.v4.view.ViewPager
        android:id="@+id/pager"
        android:layout_width="match_parent"
        android:layout_height="@dimen/pager_image_and_text_height" />
</LinearLayout>

Viewpager row xml

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

    <ImageView
        android:id="@+id/imageview_campaign"
        android:layout_width="match_parent"
        android:layout_height="@dimen/parallax_image_height"
        android:layout_marginLeft="4dp"
        android:layout_marginRight="4dp"
        android:adjustViewBounds="true"
        android:scaleType="centerCrop" />

    <TextView
        android:id="@+id/textview_campaign"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingLeft="4dp"
        android:paddingRight="4dp"
        android:paddingTop="8dp"
        android:text="Lorem ipsum dolor sit amet
aliquam nec nisi in lorem"
        android:textSize="@dimen/standart_text_size" />
</LinearLayout>
msevgi
  • 4,828
  • 2
  • 24
  • 30
  • hi how to design view with scrollable viewpager and recycler card view along with search bar when user scroll down collapse the viewpager images and changes to toolbar looks like google play store app please help me along with navigation drawer – Harsha Feb 09 '16 at 09:09
3

I had the same problem and read through all the answers here. I will describe how I solve this.

Just some background, I have a viewpager with tabs at the top that displays 3 fragments when the app starts up.

Inside one of the fragment is a recyclerview with a viewpager as one of the items in the view - lets call that Fragment A:

I call this inside Fragment A to set the RECYCLERVIEW adapter:

FragmentOuterAdapter fragmentOuterAdapter  = new FragmentOuterAdapter(getActivity(), this ); //this here refers to Fragment A - note this as this is IMPORTANT
mRecyclerView.setAdapter(fragmentOuterAdapter);

Inside my RECYCLERVIEW adapter, I call the following to create the viewHolder:

class ViewPagerViewHolder extends RecyclerView.ViewHolder {
    ViewPager viewPager;
    public ViewPagerViewHolder(View view) {
        super(view);
        viewPager = (ViewPager) view.findViewById(R.id.viewPager);
    }
}

Under onCreateViewHolder, I initialise the view and get a handle on it.

The important piece of code comes under onBindViewHolder:

        FragmentManager fragmentManager = fragment.getChildFragmentManager();
        ((ViewPagerViewHolder) holder).viewPager.setAdapter(new SubViewFragmentPagerAdapter(fragmentManager));

The fragment object that was passed in FragmentOuterAdapter appears here where I'm using the object to getChildFragmentManager().

Because you are using displaying a fragment inside a fragment THROUGH the viewpager, you need to use the child fragment manager instead of the fragmentmanager.

This will make the viewpager work.

Simon
  • 19,658
  • 27
  • 149
  • 217
1

Only way worked for me is to use something new that came up in Android Support Library v7 is to use Horizontal Recyclerview with PagerSnapHelper to get similar results as that of ViewPager

RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
recyclerview.setLayoutManager(new LinearLayoutManager(context,
                        LinearLayoutManager.HORIZONTAL,false));
recyclerview.setAdapter(adapter);
SnapHelper snapHelper = new PagerSnapHelper();
snapHelper.attachToRecyclerView(recyclerView);
Shyam Sunder
  • 523
  • 4
  • 13
0

Try setting your ViewPager to have a hard coded height rather than wrap-content or match-parent. I had a strange issue where my screen would be blank even though my ViewPager was populated.

0

As the second row you have to use a linear layout and inside that add the view pager along with the tabhost widget that shows the comments and likes fragments.

You could use the library https://github.com/daimajia/AndroidSwipeLayout found here to achieve the same effect in a more simpler way.

I could provide more details if you are interested.

codename_47
  • 449
  • 2
  • 17
0

The answer given by Linh Nguyen fixed it for me, although I had a slightly different case from the original question.

In a Activity I had RecyclerView with rows:
ROW1: ViewPager with X images (layout_height="200dp")
ROW2: text
ROW3: ViewPager with Y images (layout_height="100dp")
...

Because I was reusing the same layout for ROW1 and ROW3, both ViewPagers had the same @+id.
The ViewPager in ROW1 worked fine.
But ViewPager in ROW3 behaved like this:

  • Upon initial screen load ViewPager page creation method would be called (onCreateView() for the first and the two surrounding pages/Fragments of ViewPager in ROW3)
  • It seemed as if nothing got rendered (empty pages)

But then I noticed that if I had 5+ images in ROW3 I could swipe through empty pages and eventually I would could see pages 3, 4 and so forth. Once I reached the end, going back to the pages 2 and 1 would be created properly (because they got re-created).

After giving ViewPager in ROW3 a unique ID everything started working just fine.

Community
  • 1
  • 1
trav3ll3r
  • 30
  • 1
  • 6
-1

To answer to your first question "What's wrong with my implementation."

you did set android:orientation="vertical" in RelativeLayout and in your FrameLayout.

Maybe the fix is to not them in there. Please let me know if that is the suitable fix.

Marko
  • 20,385
  • 13
  • 48
  • 64