Jude Fernandes
Jude Fernandes

Reputation: 7517

Sticky header/item in recyclerview

I have successfully implemented sections in a recycler view as shown in the screenshot with two different types of views. How do i implement a sticky header in the recycler view. I want the 'A' to stick to the top until the user scrolls upwards in which case the next item to stick to the top would be 'B'. How do i do this?

Recycler View

Upvotes: 4

Views: 10673

Answers (1)

KlaasNotFound
KlaasNotFound

Reputation: 1075

You will definitely want to use a library for this. Emil Sjölander's StickyListHeaders is a good choice (I've used it in several projects), but there are also other libraries out there.

Not knowing the specifics of your code, here's a rough sketch of how you would do it with StickyListHeaders:

  • Create a layout for your items and headers (you probably already have that). Let's assume these are called item_cheese.xml and item_header.xml.

  • Replace your ListView with a StickyListHeadersListView in your layout file.

  • Create a custom Adapter for your collection of cheeses (you probably already have that) and make it implement StickyListHeadersAdapter.

The interface adds only two methods:

public interface StickyListHeadersAdapter extends ListAdapter {
    View getHeaderView(int position, View view, ViewGroup parent);
    long getHeaderId(int position);
}

The full implementation of your adapter would look as follows. It is using ViewHolders for both the items and the headers (to recycle views, like you asked):

public class CheeseAdapter extends BaseAdapter implements StickyListHeadersAdapter {

    private List<String> cheeses;
    private final LayoutInflater inflater;

    public CheeseAdapter(Context context, List<String> cheeses) {
        // Assuming cheeses are already alphabetically sorted at this point
        this.cheeses = cheeses;
        this.inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }

    @Override
    public int getCount() {
        return (cheeses != null) ? cheeses.size() : 0;
    }

    @Override
    public Object getItem(int position) {
        return cheeses.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View view, ViewGroup parent) {
        CheeseViewHolder holder;
        if (view != null)
            holder = (CheeseViewHolder) view.getTag();
        else {
            view = inflater.inflate(R.layout.item_cheese, parent, false);
            holder = new CheeseViewHolder(view);
            view.setTag(holder);
        }
        holder.decorate(cheeses.get(position));
        return view;
    }

    @Override
    public long getHeaderId(int position) {
        // Return the first char of each item as its header ID
        return cheeses.get(position).charAt(0);
    }

    @Override
    public View getHeaderView(int position, View view, ViewGroup parent) {
        HeaderViewHolder holder;
        if (view != null)
            holder = (HeaderViewHolder) view.getTag();
        else {
            view = inflater.inflate(R.layout.item_header, parent, false);
            holder = new HeaderViewHolder(view);
            view.setTag(holder);
        }
        holder.decorate(cheeses.get(position));
        return view;
    }

    public class CheeseViewHolder {

        TextView tvCheeseName;

        public CheeseViewHolder(View view) {
            tvCheeseName = (TextView) view.findViewById(R.id.tvCheeseName);
        }

        public void decorate(String cheeseName) {
            if (cheeseName == null) return;
            tvCheeseName.setText(cheeseName);
        }
    }

    public class HeaderViewHolder {

        TextView tvHeader;

        public CheeseViewHolder(View view) {
            tvHeader = (TextView) view.findViewById(R.id.tvHeader);
        }

        public void decorate(String cheeseName) {
            if (cheeseName == null || cheeseName.isEmpty()) return;
            tvHeader.setText(cheeseName.toUpperCase().charAt(0));
        }
    }
}
  • Use the custom adapter in your Activity or Fragment. The ScrollView will have alphabetic sections with sticky headers and will behave just as advertised.

Simple as that.

Upvotes: 2

Related Questions