Contents
Mobile App Development: Tutorial How To Add Header to RecyclerView in Android
In the previous post, I showed you how to add header and footer to childview of an ExpandableListview. This article is also related to headers, but it’s about how to Add Header to RecyclerView.
RecyclerView is the upgrade of ListView and there are a lot of advantages compared to ListView such as CardView and ViewHolder. CardView allows us to create a complex and friendly UI easily while ViewHolder pattern helps to avoid looking up the UI components all the time the system shows a row. However, it does come with some disadvantages. One of the disadvantages is without support methods such as addHeaderView() or addFooterView() like a ListView do.
I tried to look around on the internet for a completed example showing how to add header to RecyclerView but I couldn’t find one. Here we share an example with you which will show you a header with a text on it and following it is a list of an image and its name.
This example is written in Android Studio with the version of 1.2.2.
Ho Ngoc Trang, trangho214@gmail.com, is the author of this article and she contributes to RobustTechHouse Blog.
1. Adding support library
To get RecyclerView and CardView to work on the previous version of Lollipop we need to add support libraries to gradle.
compile 'com.android.support:recyclerview-v7:22.2.0' compile 'com.android.support:cardview-v7:22.2.0'
2. Creating RecyclerView
Using a RecyclerView instance is slightly more complicated. However, defining it in a layout XML file is quite simple. You can define it in a layout as follows:
main_activity.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity"> <android.support.v7.widget.RecyclerView android:id="@+id/my_recycler_view" android:scrollbars="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> </android.support.v7.widget.RecyclerView> </RelativeLayout>
3. Creating CardView
CardView in this case acts like a list_item. It holds all UI components we need for an item showed in the RecyclerView.
header_item.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:card_view="http://schemas.android.com/apk/res-auto" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v7.widget.CardView android:layout_width = "match_parent" android:layout_height = "wrap_content" card_view:contentPadding="@dimen/activity_horizontal_margin" card_view:cardCornerRadius="3dp"> <TextView android:id="@+id/txtHeader" android:gravity="center" android:textColor="@android:color/primary_text_dark" android:background="@drawable/rectangle" android:textSize="@dimen/abc_text_size_large_material" android:layout_width="match_parent" android:layout_height="50dp" /> </android.support.v7.widget.CardView> </LinearLayout>
list_item.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:card_view="http://schemas.android.com/apk/res-auto" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v7.widget.CardView android:layout_width = "match_parent" android:layout_height = "wrap_content" android:layout_margin = "4dp" card_view:contentPadding="@dimen/activity_horizontal_margin" card_view:cardCornerRadius="3dp"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <TextView android:id="@+id/txtName" android:text="abc" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <ImageView android:layout_marginBottom="10dp" android:id="@+id/ivListItem" android:layout_width="match_parent" android:layout_height="wrap_content" /> </LinearLayout> </android.support.v7.widget.CardView> </LinearLayout>
4. Classes
We need two classes, which represents two objects working with header and list item. I named these classes Header and ListItem. For simplicity, I just made the Header class with one field. However you can modify it to meet your needs by adding more fields or change the type of field. ListItem class has two fields – a name and an id. Id represents image and name is the name of image, which will show in each item of the list.
Header Class
public class Header { // More fields can be defined here after your need private String header; public Header(){} public String getHeader() { return header; } public void setHeader(String header) { this.header = header; } }
ListItem Class
public class ListItem { private String name; public ListItem(){} public String getName() { return name; } public void setName(String name) { this.name = name; } private int id; public int getId() { return id; } public void setId(int id) { this.id = id; } }
5. Custom Adapter
We will create an adapter for our RecyclerView. This adapter must extend RecyclerView.Adapter which is followed by a ViewHolder pattern. As mentioned above, ViewHolder will help the system avoid calling findViewById method every time it shows a row.
MyRecyclerAdapter class
public class MyRecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { private static final int TYPE_HEADER = 0; private static final int TYPE_ITEM = 1; Header header; List<ListItem> listItems; public MyRecyclerAdapter(Header header, List<ListItem> listItems) { this.header = header; this.listItems = listItems; } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { if(viewType == TYPE_HEADER) { View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.header_item, parent, false); return new VHHeader(v); } else if(viewType == TYPE_ITEM) { View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item, parent, false); return new VHItem(v); } throw new RuntimeException("there is no type that matches the type " + viewType + " + make sure your using types correctly"); } private ListItem getItem(int position) { return listItems.get(position); } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { if(holder instanceof VHHeader) { VHHeader VHheader = (VHHeader)holder; VHheader.txtTitle.setText(header.getHeader()); } else if(holder instanceof VHItem) { ListItem currentItem = getItem(position-1); VHItem VHitem = (VHItem)holder; VHitem.txtName.setText(currentItem.getName()); VHitem.iv.setBackgroundResource(currentItem.getId()); } } // need to override this method @Override public int getItemViewType(int position) { if(isPositionHeader(position)) return TYPE_HEADER; return TYPE_ITEM; } private boolean isPositionHeader(int position) { return position == 0; } //increasing getItemcount to 1. This will be the row of header. @Override public int getItemCount() { return listItems.size()+1; } class VHHeader extends RecyclerView.ViewHolder{ TextView txtTitle; public VHHeader(View itemView) { super(itemView); this.txtTitle = (TextView)itemView.findViewById(R.id.txtHeader); } } class VHItem extends RecyclerView.ViewHolder{ TextView txtName; ImageView iv; public VHItem(View itemView) { super(itemView); this.txtName = (TextView)itemView.findViewById(R.id.txtName); this.iv = (ImageView)itemView.findViewById(R.id.ivListItem); } } }
6. Main Activity
In this class I have already created dummy data to use for our RecyclerView. Now all we need to do to complete this job is make an instance of Adapter and pass it to our RecyclerView and see what we will get.
Main Activity Class
public class MainActivity extends AppCompatActivity { RecyclerView recyclerView; LinearLayoutManager linearLayoutManager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); recyclerView = (RecyclerView)findViewById(R.id.my_recycler_view); linearLayoutManager = new LinearLayoutManager(this); MyRecyclerAdapter adapter = new MyRecyclerAdapter(getHeader(), getListItems()); recyclerView.setLayoutManager(linearLayoutManager); recyclerView.setAdapter(adapter); } public Header getHeader() { Header header = new Header(); header.setHeader("I'm header"); return header; } public List<ListItem> getListItems() { List<ListItem> listItems = new ArrayList<ListItem>(); for (int i = 0; i<10; i++) { ListItem item = new ListItem(); item.setName("image" + i); if (i % 2 == 0) item.setId(R.drawable.sweetlife); else item.setId(R.drawable.young); listItems.add(item); } return listItems; } }
7. Output
Conclusion
Here we have a post related to how to Add Header to RecyclerView. I didn’t show footers specifically in this post because the same principles apply. Hope you find this post useful.
The completed project can be downloaded here.
If you like our articles, please follow and like our Facebook page where we regularly share interesting posts and check out our other blog articles.
RobustTechHouse is a leading tech company focusing on mobile app development in Singapore. If you are interested to engage RobustTechHouse for your projects, you can contact us here.
have been searching for a solution from long, this is the only clean and effective of adding headers in recycler view.. Thanks a lot!