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 List people = 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 List getPeople() {
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