Android RecyclerView with sticky header using ItemDecoration
The sticky header layout, recycler_section_header.xml
The RecyclerView list item layout, list_item.xml
The main layout, activity_main.xml
The activity class, MainActivity.java
public class MainActivity extends AppCompatActivity { RecyclerView recyclerView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); recyclerView = (RecyclerView) findViewById(R.id.rv_list); recyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)); final Listpeople = PeopleRepo.getPeopleSorted(); recyclerView.setAdapter(new PersonAdapter(people, R.layout.list_item)); RecyclerSectionItemDecoration sectionItemDecoration = new RecyclerSectionItemDecoration(getResources().getDimensionPixelSize(R.dimen.recycler_section_header_height), true, getSectionCallback(people)); recyclerView.addItemDecoration(sectionItemDecoration); } private RecyclerSectionItemDecoration.SectionCallback getSectionCallback(final List people) { return new RecyclerSectionItemDecoration.SectionCallback() { @Override public boolean isSection(int position) { return position == 0 || people.get(position) .getLastName() .charAt(0) != people.get(position - 1) .getLastName() .charAt(0); } @Override public CharSequence getSectionHeader(int position) { return people.get(position) .getLastName() .subSequence(0, 1); } }; } }
The Adapter for the RecyclerView, PersonAdapter.java
public class PersonAdapter extends RecyclerView.Adapter{ private final List people; private final int rowLayout; public PersonAdapter(List people, @LayoutRes int rowLayout) { this.people = people; this.rowLayout = rowLayout; } @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(rowLayout, parent, false); return new ViewHolder(view); } @Override public void onBindViewHolder(ViewHolder holder, int position) { Person person = people.get(position); holder.fullName.setText(person.getFullName()); } @Override public int getItemCount() { return people.size(); } public static class ViewHolder extends RecyclerView.ViewHolder { private TextView fullName; public ViewHolder(View view) { super(view); fullName = (TextView) view.findViewById(R.id.tv_text); } } }
The ItemDecoration class for the sticky header RecyclerSectionItemDecoration.java
import android.graphics.Canvas; import android.graphics.Rect; import android.support.annotation.NonNull; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; /** * https://github.com/paetztm/recycler_view_headers */ public class RecyclerSectionItemDecoration extends RecyclerView.ItemDecoration { private final int headerOffset; private final boolean sticky; private final SectionCallback sectionCallback; private View headerView; private TextView header; public RecyclerSectionItemDecoration(int headerHeight, boolean sticky, @NonNull SectionCallback sectionCallback) { headerOffset = headerHeight; this.sticky = sticky; this.sectionCallback = sectionCallback; } @Override public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { super.getItemOffsets(outRect, view, parent, state); int pos = parent.getChildAdapterPosition(view); if (sectionCallback.isSection(pos)) { outRect.top = headerOffset; } } @Override public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) { super.onDrawOver(c, parent, state); if (headerView == null) { headerView = inflateHeaderView(parent); header = (TextView) headerView.findViewById(R.id.list_item_section_text); fixLayoutSize(headerView, parent); } CharSequence previousHeader = ""; for (int i = 0; i < parent.getChildCount(); i++) { View child = parent.getChildAt(i); final int position = parent.getChildAdapterPosition(child); CharSequence title = sectionCallback.getSectionHeader(position); header.setText(title); if (!previousHeader.equals(title) || sectionCallback.isSection(position)) { drawHeader(c, child, headerView); previousHeader = title; } } } private void drawHeader(Canvas c, View child, View headerView) { c.save(); if (sticky) { c.translate(0, Math.max(0, child.getTop() - headerView.getHeight())); } else { c.translate(0, child.getTop() - headerView.getHeight()); } headerView.draw(c); c.restore(); } private View inflateHeaderView(RecyclerView parent) { return LayoutInflater.from(parent.getContext()) .inflate(R.layout.recycler_section_header, parent, false); } /** * Measures the header view to make sure its size is greater than 0 and will be drawn * https://yoda.entelect.co.za/view/9627/how-to-android-recyclerview-item-decorations */ private void fixLayoutSize(View view, ViewGroup parent) { int widthSpec = View.MeasureSpec.makeMeasureSpec(parent.getWidth(), View.MeasureSpec.EXACTLY); int heightSpec = View.MeasureSpec.makeMeasureSpec(parent.getHeight(), View.MeasureSpec.UNSPECIFIED); int childWidth = ViewGroup.getChildMeasureSpec(widthSpec, parent.getPaddingLeft() + parent.getPaddingRight(), view.getLayoutParams().width); int childHeight = ViewGroup.getChildMeasureSpec(heightSpec, parent.getPaddingTop() + parent.getPaddingBottom(), view.getLayoutParams().height); view.measure(childWidth, childHeight); view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight()); } public interface SectionCallback { boolean isSection(int position); CharSequence getSectionHeader(int position); } }
The dummy object class, Person.java
import android.support.annotation.NonNull; import java.util.Locale; public class Person implements Comparable{ private final CharSequence firstName; private final CharSequence lastName; private static final String NAME_DISPLAY = "%s, %s"; public Person(@NonNull CharSequence firstName, @NonNull CharSequence lastName) { this.firstName = firstName; this.lastName = lastName; } public CharSequence getLastName() { return lastName; } public CharSequence getFirstName() { return firstName; } public String getFullName() { return String.format(Locale.getDefault(), NAME_DISPLAY, getLastName(), getFirstName()); } @Override public int compareTo(@NonNull Person person) { return getLastName().toString() .compareTo(person.getLastName() .toString()); } }
The data creation class, PeopleRepo.java
import java.util.ArrayList; import java.util.Collections; import java.util.List; public class PeopleRepo { public static ListgetPeople() { List people = new ArrayList<>(45); people.add(new Person("George", "Washington")); people.add(new Person("John", "Adams")); people.add(new Person("Thomas", "Jefferson")); people.add(new Person("James", "Madison")); people.add(new Person("James", "Monroe")); people.add(new Person("John Quincy", "Adams")); people.add(new Person("Andrew", "Jackson")); people.add(new Person("Martin", "Van Buren")); people.add(new Person("William", "Harrison")); people.add(new Person("John", "Tyler")); people.add(new Person("Zachary", "Taylor")); people.add(new Person("Millard", "Fillmore")); people.add(new Person("Franklin", "Pierce")); people.add(new Person("James", "Buchanan")); people.add(new Person("Abraham", "Lincoln")); people.add(new Person("Andrew", "Johnson")); people.add(new Person("Ulysses", "Grant")); people.add(new Person("Rutherford", "Hayes")); people.add(new Person("James", "Garfield")); people.add(new Person("Chester", "Arthur")); people.add(new Person("Grover", "Cleveland")); people.add(new Person("Benjamin", "Harrison")); people.add(new Person("William", "McKinley")); people.add(new Person("Theodore", "Roosevelt")); people.add(new Person("William", "Taft")); people.add(new Person("Woodrow", "Wilson")); people.add(new Person("Warren", "Harding")); people.add(new Person("Calvin", "Coolidge")); people.add(new Person("Herbert", "Hoover")); people.add(new Person("Harry", "Truman")); people.add(new Person("Dwight", "Eisenhower")); people.add(new Person("John", "Kennedy")); people.add(new Person("Lyndon", "Johnson")); people.add(new Person("Richard", "Nixon")); people.add(new Person("Gerald", "Ford")); people.add(new Person("Jimmy", "Carter")); people.add(new Person("Ronald", "Reagan")); people.add(new Person("George H.W.", "Bush")); people.add(new Person("Bill", "Clinton")); people.add(new Person("George W.", "Bush")); people.add(new Person("Barack", "Obama")); people.add(new Person("Donald", "Trump")); return people; } public static List getPeopleSorted() { List people = getPeople(); Collections.sort(people); return people; } }
Complete example in Github
Reference:
https://github.com/paetztm/recycler_view_headers
Search within Codexpedia
Custom Search
Search the entire web
Custom Search
Related Posts