How to implement RecyclerView with CardView rows in a Fragment with TabLayout
Here is a simple example using a TabLayout and a RecyclerView with a CardView in each row.
First, MainActivity, which sets up the ViewPager and TabLayout:
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); // Get the ViewPager and set it's PagerAdapter so that it can display items ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager); PagerAdapter pagerAdapter = new PagerAdapter(getSupportFragmentManager(), MainActivity.this); viewPager.setAdapter(pagerAdapter); // Give the TabLayout the ViewPager TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout); tabLayout.setupWithViewPager(viewPager); // Iterate over all tabs and set the custom view for (int i = 0; i < tabLayout.getTabCount(); i++) { TabLayout.Tab tab = tabLayout.getTabAt(i); tab.setCustomView(pagerAdapter.getTabView(i)); } } @Override public void onResume() { super.onResume(); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.menu_main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } class PagerAdapter extends FragmentPagerAdapter { String tabTitles[] = new String[] { "Tab One", "Tab Two", "Tab Three" }; Context context; public PagerAdapter(FragmentManager fm, Context context) { super(fm); this.context = context; } @Override public int getCount() { return tabTitles.length; } @Override public Fragment getItem(int position) { switch (position) { case 0: return new BlankFragment(); case 1: return new BlankFragment(); case 2: return new BlankFragment(); } return null; } @Override public CharSequence getPageTitle(int position) { // Generate title based on item position return tabTitles[position]; } public View getTabView(int position) { View tab = LayoutInflater.from(MainActivity.this).inflate(R.layout.custom_tab, null); TextView tv = (TextView) tab.findViewById(R.id.custom_text); tv.setText(tabTitles[position]); return tab; } }}
activity_main.xml:
<RelativeLayout android:id="@+id/main_layout" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:background="?attr/colorPrimary" android:elevation="6dp" android:minHeight="?attr/actionBarSize" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" app:popupTheme="@style/ThemeOverlay.AppCompat.Light" /> <android.support.design.widget.TabLayout android:id="@+id/tab_layout" app:tabMode="fixed" android:layout_below="@+id/toolbar" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="?attr/colorPrimary" android:elevation="6dp" app:tabTextColor="#d3d3d3" app:tabSelectedTextColor="#ffffff" app:tabIndicatorColor="#ff00ff" android:minHeight="?attr/actionBarSize" /> <android.support.v4.view.ViewPager android:id="@+id/viewpager" android:layout_below="@+id/tab_layout" android:layout_width="match_parent" android:layout_height="wrap_content" /></RelativeLayout>
custom_tab.xml for each Tab in the TabLayout:
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/custom_text" android:layout_width="match_parent" android:layout_height="match_parent" android:background="?attr/selectableItemBackground" android:gravity="center" android:textSize="16dip" android:textColor="#ffffff" android:singleLine="true" /></LinearLayout>
Here is the BlankFragment class, which uses a RecyclerView to show a list:
import android.support.v4.app.Fragment;import android.support.v7.widget.LinearLayoutManager;import android.support.v7.widget.RecyclerView;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;;public class BlankFragment extends Fragment { public BlankFragment() { // Required empty public constructor } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment View rootView = inflater.inflate(R.layout.fragment_blank, container, false); RecyclerView rv = (RecyclerView) rootView.findViewById(R.id.rv_recycler_view); rv.setHasFixedSize(true); MyAdapter adapter = new MyAdapter(new String[]{"test one", "test two", "test three", "test four", "test five" , "test six" , "test seven"}); rv.setAdapter(adapter); LinearLayoutManager llm = new LinearLayoutManager(getActivity()); rv.setLayoutManager(llm); return rootView; }}
fragment_blank.xml:
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v7.widget.RecyclerView android:id="@+id/rv_recycler_view" android:layout_width="match_parent" android:layout_height="match_parent" > </android.support.v7.widget.RecyclerView></RelativeLayout>
card_item.xml for the RecyclerView list:
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="68dp" > <android.support.v7.widget.CardView android:id="@+id/card_view" xmlns:card_view="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_margin="10dp" android:layout_height="62dp" card_view:cardCornerRadius="4dp" card_view:elevation="14dp"> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent"> <ImageView android:id="@+id/iv_image" android:layout_height="wrap_content" android:layout_width="wrap_content" android:src="@drawable/abc_btn_radio_material"> </ImageView> <TextView android:id="@+id/tv_text" android:layout_toRightOf ="@+id/iv_image" android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="center" > </TextView> <TextView android:id="@+id/tv_blah" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="blah blah blah......" android:layout_below="@+id/tv_text" android:layout_toRightOf="@+id/iv_image" android:layout_toEndOf="@+id/iv_image"> </TextView> </RelativeLayout> </android.support.v7.widget.CardView></RelativeLayout>
MyAdapter class for the RecyclerView, this is very basic and just sets the text in one of the TextViews:
import android.support.v7.widget.CardView;import android.support.v7.widget.RecyclerView;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.TextView;public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> { private String[] mDataset; // Provide a reference to the views for each data item // Complex data items may need more than one view per item, and // you provide access to all the views for a data item in a view holder public static class MyViewHolder extends RecyclerView.ViewHolder { public CardView mCardView; public TextView mTextView; public MyViewHolder(View v) { super(v); mCardView = (CardView) v.findViewById(R.id.card_view); mTextView = (TextView) v.findViewById(R.id.tv_text); } } // Provide a suitable constructor (depends on the kind of dataset) public MyAdapter(String[] myDataset) { mDataset = myDataset; } // Create new views (invoked by the layout manager) @Override public MyAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { // create a new view View v = LayoutInflater.from(parent.getContext()) .inflate(R.layout.card_item, parent, false); // set the view's size, margins, paddings and layout parameters MyViewHolder vh = new MyViewHolder(v); return vh; } @Override public void onBindViewHolder(MyViewHolder holder, final int position) { holder.mTextView.setText(mDataset[position]); holder.mCardView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { String currentValue = mDataset[position]; Log.d("CardView", "CardView Clicked: " + currentValue); } }); } @Override public int getItemCount() { return mDataset.length; }}
Gradle dependencies used:
dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:appcompat-v7:23.0.1' compile 'com.android.support:design:23.0.1' compile 'com.android.support:cardview-v7:23.0.1' compile 'com.android.support:recyclerview-v7:23.0.1'}
Here is the result: