Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@sebnapi
Last active November 30, 2019 05:31
Show Gist options
  • Star 25 You must be signed in to star a gist
  • Fork 14 You must be signed in to fork a gist
  • Save sebnapi/fde648c17616d9d3bcde to your computer and use it in GitHub Desktop.
Save sebnapi/fde648c17616d9d3bcde to your computer and use it in GitHub Desktop.
/*
* Copyright (C) 2014 sebnapi
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import android.support.v7.widget.RecyclerView;
import android.view.ViewGroup;
/**
* Created by sebnapi on 08.11.14.
* <p/>
* If you extend this Adapter you are able to add a Header, a Footer or both
* by a similar ViewHolder pattern as in RecyclerView.
* <p/>
* If you want to omit changes to your class hierarchy you can try the Plug-and-Play
* approach HeaderRecyclerViewAdapterV1.
* <p/>
* Don't override (Be careful while overriding)
* - onCreateViewHolder
* - onBindViewHolder
* - getItemCount
* - getItemViewType
* <p/>
* You need to override the abstract methods introduced by this class. This class
* is not using generics as RecyclerView.Adapter make yourself sure to cast right.
* <p/>
* TOTALLY UNTESTED - USE WITH CARE - HAVE FUN :)
*/
public abstract class HeaderRecyclerViewAdapterV2 extends RecyclerView.Adapter {
private static final int TYPE_HEADER = Integer.MIN_VALUE;
private static final int TYPE_FOOTER = Integer.MIN_VALUE + 1;
private static final int TYPE_ADAPTEE_OFFSET = 2;
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == TYPE_HEADER) {
return onCreateHeaderViewHolder(parent, viewType);
} else if (viewType == TYPE_FOOTER) {
return onCreateFooterViewHolder(parent, viewType);
}
return onCreateBasicItemViewHolder(parent, viewType - TYPE_ADAPTEE_OFFSET);
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (position == 0 && holder.getItemViewType() == TYPE_HEADER) {
onBindHeaderView(holder, position);
} else if (position == getBasicItemCount() && holder.getItemViewType() == TYPE_FOOTER) {
onBindFooterView(holder, position);
} else {
onBindBasicItemView(holder, position - (useHeader() ? 1 : 0));
}
}
@Override
public int getItemCount() {
int itemCount = getBasicItemCount();
if (useHeader()) {
itemCount += 1;
}
if (useFooter()) {
itemCount += 1;
}
return itemCount;
}
@Override
public int getItemViewType(int position) {
if (position == 0 && useHeader()) {
return TYPE_HEADER;
}
if (position == getBasicItemCount() && useFooter()) {
return TYPE_FOOTER;
}
if (getBasicItemType(position) >= Integer.MAX_VALUE - TYPE_ADAPTEE_OFFSET) {
new IllegalStateException("HeaderRecyclerViewAdapter offsets your BasicItemType by " + TYPE_ADAPTEE_OFFSET + ".");
}
return getBasicItemType(position) + TYPE_ADAPTEE_OFFSET;
}
public abstract boolean useHeader();
public abstract RecyclerView.ViewHolder onCreateHeaderViewHolder(ViewGroup parent, int viewType);
public abstract void onBindHeaderView(RecyclerView.ViewHolder holder, int position);
public abstract boolean useFooter();
public abstract RecyclerView.ViewHolder onCreateFooterViewHolder(ViewGroup parent, int viewType);
public abstract void onBindFooterView(RecyclerView.ViewHolder holder, int position);
public abstract RecyclerView.ViewHolder onCreateBasicItemViewHolder(ViewGroup parent, int viewType);
public abstract void onBindBasicItemView(RecyclerView.ViewHolder holder, int position);
public abstract int getBasicItemCount();
/**
* make sure you don't use [Integer.MAX_VALUE-1, Integer.MAX_VALUE] as BasicItemViewType
*
* @param position
* @return
*/
public abstract int getBasicItemType(int position);
}
@goonerDroid
Copy link

works fine for me.Thanks!

@marutib
Copy link

marutib commented Jun 13, 2015

getItemViewType is broken you can modify it to :-

  @Override
  public int getItemViewType(int position) {
    if (position == 0 && useHeader()) {
      return TYPE_HEADER;
    }
    if (position == getBasicItemCount() && useFooter()) {
      return TYPE_FOOTER;
    }
    int basicItemType = getBasicItemType(position - (useHeader() ? 1 : 0));
    if (basicItemType >= Integer.MAX_VALUE - TYPE_ADAPTEE_OFFSET) {
      new IllegalStateException(
          "HeaderRecyclerViewAdapter offsets your BasicItemType by " + TYPE_ADAPTEE_OFFSET + ".");
    }
    return basicItemType + TYPE_ADAPTEE_OFFSET;
  }

@manjunathc23
Copy link

@marutib 👍 Thanks

if (position >= getBasicItemCount() && useFooter()) { return TYPE_FOOTER; }

This should be change in the last comment! otherwise we may run in out of bound exception

@snm114
Copy link

snm114 commented Sep 9, 2015

It has been working perfectly until I tried to use both footer and header.
When I used both of them, the last item of basic items was processed as a footer, which caused crashes when I scrolled down to the last item...

I modified following two methods to fix this. Hope this is a right way to do it... :)

public int getItemViewType(int position) {
    if (position == 0 && useHeader()) {
        return TYPE_HEADER;
    }

    if (useHeader() && position > getBasicItemCount() && useFooter())
        return TYPE_FOOTER;
    else if (!useHeader() && position > getBasicItemCount() && useFooter())
        return TYPE_FOOTER;

    int basicItemType = getBasicItemType(position - (useHeader() ? 1 : 0));

    if (basicItemType >= Integer.MAX_VALUE - TYPE_ADAPTEE_OFFSET) {
        new IllegalStateException(
                "HeaderRecyclerViewAdapter offsets your BasicItemType by " + TYPE_ADAPTEE_OFFSET + ".");
    }

    return basicItemType + TYPE_ADAPTEE_OFFSET;
}

public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
    if (position == 0 && holder.getItemViewType() == TYPE_HEADER) {
        onBindHeaderView(holder, position);
    } else if (useHeader() && position > getBasicItemCount() && holder.getItemViewType() == TYPE_FOOTER) {
        onBindFooterView(holder, position);
    } else if (!useHeader() && position >= getBasicItemCount() && holder.getItemViewType() == TYPE_FOOTER) {
        onBindFooterView(holder, position);
    }
    else {
        onBindBasicItemView(holder, position - (useHeader() ? 1 : 0));
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment