-
-
Save saber-solooki/edeb57be63d2a60ef551676067c66c71 to your computer and use it in GitHub Desktop.
| package com.saber.customstickyheader; | |
| import android.graphics.Color; | |
| 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; | |
| import java.util.ArrayList; | |
| import java.util.List; | |
| public class SimpleRecyclerView extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements StickHeaderItemDecoration.StickyHeaderInterface { | |
| private List<Data> mData; | |
| public SimpleRecyclerView() { | |
| mData = new ArrayList<>(); | |
| mData.add(new Data(1)); | |
| mData.add(new Data(0)); | |
| mData.add(new Data(0)); | |
| mData.add(new Data(0)); | |
| mData.add(new Data(0));` | |
| mData.add(new Data(0)); | |
| mData.add(new Data(2)); | |
| mData.add(new Data(0)); | |
| mData.add(new Data(0)); | |
| mData.add(new Data(0)); | |
| mData.add(new Data(0)); | |
| mData.add(new Data(0)); | |
| mData.add(new Data(0)); | |
| mData.add(new Data(1)); | |
| mData.add(new Data(0)); | |
| mData.add(new Data(0)); | |
| mData.add(new Data(0)); | |
| mData.add(new Data(0)); | |
| mData.add(new Data(0)); | |
| mData.add(new Data(0)); | |
| mData.add(new Data(2)); | |
| mData.add(new Data(0)); | |
| mData.add(new Data(0)); | |
| mData.add(new Data(0)); | |
| mData.add(new Data(0)); | |
| mData.add(new Data(0)); | |
| } | |
| @NonNull | |
| @Override | |
| public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { | |
| switch (viewType) { | |
| case HeaderDataImpl.HEADER_TYPE_1: | |
| return new SimpleRecyclerView.HeaderViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.header1_item_recycler, parent, false)); | |
| case HeaderDataImpl.HEADER_TYPE_2: | |
| return new SimpleRecyclerView.Header2ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.header2_item_recycler, parent, false)); | |
| default: | |
| return new SimpleRecyclerView.ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_recycler, parent, false)); | |
| } | |
| } | |
| @Override | |
| public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { | |
| if (holder instanceof ViewHolder) { | |
| ((ViewHolder) holder).bindData(position); | |
| } else if (holder instanceof HeaderViewHolder){ | |
| ((HeaderViewHolder) holder).bindData(position); | |
| } else if (holder instanceof Header2ViewHolder){ | |
| ((Header2ViewHolder) holder).bindData(position); | |
| } | |
| } | |
| @Override | |
| public int getItemViewType(int position) { | |
| return mData.get(position).getViewType(); | |
| } | |
| @Override | |
| public int getItemCount() { | |
| return mData.size(); | |
| } | |
| @Override | |
| public int getHeaderPositionForItem(int itemPosition) { | |
| int headerPosition = 0; | |
| do { | |
| if (this.isHeader(itemPosition)) { | |
| headerPosition = itemPosition; | |
| break; | |
| } | |
| itemPosition -= 1; | |
| } while (itemPosition >= 0); | |
| return headerPosition; | |
| } | |
| @Override | |
| public int getHeaderLayout(int headerPosition) { | |
| if (mData.get(headerPosition).getViewType() == 1) | |
| return R.layout.header1_item_recycler; | |
| else { | |
| return R.layout.header2_item_recycler; | |
| } | |
| } | |
| @Override | |
| public void bindHeaderData(View header, int headerPosition) { | |
| } | |
| @Override | |
| public boolean isHeader(int itemPosition) { | |
| if (mData.get(itemPosition).getViewType() == 1 || mData.get(itemPosition).getViewType() == 2) | |
| return true; | |
| else | |
| return false; | |
| } | |
| class HeaderViewHolder extends RecyclerView.ViewHolder { | |
| TextView tvHeader; | |
| HeaderViewHolder(View itemView) { | |
| super(itemView); | |
| tvHeader = itemView.findViewById(R.id.tvHeader); | |
| } | |
| void bindData(int position) { | |
| tvHeader.setText(String.valueOf(position / 5)); | |
| } | |
| } | |
| class Header2ViewHolder extends RecyclerView.ViewHolder { | |
| TextView tvHeader; | |
| Header2ViewHolder(View itemView) { | |
| super(itemView); | |
| tvHeader = itemView.findViewById(R.id.tvHeader); | |
| } | |
| void bindData(int position) { | |
| tvHeader.setText(String.valueOf(position / 5)); | |
| } | |
| } | |
| class ViewHolder extends RecyclerView.ViewHolder { | |
| TextView tvRows; | |
| ViewHolder(View itemView) { | |
| super(itemView); | |
| tvRows = itemView.findViewById(R.id.tvRows); | |
| } | |
| void bindData(int position) { | |
| tvRows.setText("saber" + position); | |
| ((ViewGroup) tvRows.getParent()).setBackgroundColor(Color.parseColor("#ffffff")); | |
| } | |
| } | |
| class Data { | |
| int viewType; | |
| public Data(int viewType) { | |
| this.viewType = viewType; | |
| } | |
| public int getViewType() { | |
| return viewType; | |
| } | |
| public void setViewType(int viewType) { | |
| this.viewType = viewType; | |
| } | |
| } | |
| } |
| package com.saber.customstickyheader; | |
| import android.graphics.Canvas; | |
| import android.support.annotation.NonNull; | |
| import android.support.v7.widget.RecyclerView; | |
| import android.view.LayoutInflater; | |
| import android.view.View; | |
| import android.view.ViewGroup; | |
| public class StickHeaderItemDecoration extends RecyclerView.ItemDecoration { | |
| private StickyHeaderInterface mListener; | |
| private int mStickyHeaderHeight; | |
| public StickHeaderItemDecoration(@NonNull StickyHeaderInterface listener) { | |
| mListener = listener; | |
| } | |
| @Override | |
| public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) { | |
| super.onDrawOver(c, parent, state); | |
| View topChild = parent.getChildAt(0); | |
| if (topChild == null) { | |
| return; | |
| } | |
| int topChildPosition = parent.getChildAdapterPosition(topChild); | |
| if (topChildPosition == RecyclerView.NO_POSITION) { | |
| return; | |
| } | |
| int headerPos = mListener.getHeaderPositionForItem(topChildPosition); | |
| View currentHeader = getHeaderViewForItem(headerPos, parent); | |
| fixLayoutSize(parent, currentHeader); | |
| int contactPoint = currentHeader.getBottom(); | |
| View childInContact = getChildInContact(parent, contactPoint, headerPos); | |
| if (childInContact != null && mListener.isHeader(parent.getChildAdapterPosition(childInContact))) { | |
| moveHeader(c, currentHeader, childInContact); | |
| return; | |
| } | |
| drawHeader(c, currentHeader); | |
| } | |
| private View getHeaderViewForItem(int headerPosition, RecyclerView parent) { | |
| int layoutResId = mListener.getHeaderLayout(headerPosition); | |
| View header = LayoutInflater.from(parent.getContext()).inflate(layoutResId, parent, false); | |
| mListener.bindHeaderData(header, headerPosition); | |
| return header; | |
| } | |
| private void drawHeader(Canvas c, View header) { | |
| c.save(); | |
| c.translate(0, 0); | |
| header.draw(c); | |
| c.restore(); | |
| } | |
| private void moveHeader(Canvas c, View currentHeader, View nextHeader) { | |
| c.save(); | |
| c.translate(0, nextHeader.getTop() - currentHeader.getHeight()); | |
| currentHeader.draw(c); | |
| c.restore(); | |
| } | |
| private View getChildInContact(RecyclerView parent, int contactPoint, int currentHeaderPos) { | |
| View childInContact = null; | |
| for (int i = 0; i < parent.getChildCount(); i++) { | |
| int heightTolerance = 0; | |
| View child = parent.getChildAt(i); | |
| //measure height tolerance with child if child is another header | |
| if (currentHeaderPos != i) { | |
| boolean isChildHeader = mListener.isHeader(parent.getChildAdapterPosition(child)); | |
| if (isChildHeader) { | |
| heightTolerance = mStickyHeaderHeight - child.getHeight(); | |
| } | |
| } | |
| //add heightTolerance if child top be in display area | |
| int childBottomPosition; | |
| if (child.getTop() > 0) { | |
| childBottomPosition = child.getBottom() + heightTolerance; | |
| } else { | |
| childBottomPosition = child.getBottom(); | |
| } | |
| if (childBottomPosition > contactPoint) { | |
| if (child.getTop() <= contactPoint) { | |
| // This child overlaps the contactPoint | |
| childInContact = child; | |
| break; | |
| } | |
| } | |
| } | |
| return childInContact; | |
| } | |
| /** | |
| * Properly measures and layouts the top sticky header. | |
| * @param parent ViewGroup: RecyclerView in this case. | |
| */ | |
| private void fixLayoutSize(ViewGroup parent, View view) { | |
| // Specs for parent (RecyclerView) | |
| int widthSpec = View.MeasureSpec.makeMeasureSpec(parent.getWidth(), View.MeasureSpec.EXACTLY); | |
| int heightSpec = View.MeasureSpec.makeMeasureSpec(parent.getHeight(), View.MeasureSpec.UNSPECIFIED); | |
| // Specs for children (headers) | |
| int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec, parent.getPaddingLeft() + parent.getPaddingRight(), view.getLayoutParams().width); | |
| int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec, parent.getPaddingTop() + parent.getPaddingBottom(), view.getLayoutParams().height); | |
| view.measure(childWidthSpec, childHeightSpec); | |
| view.layout(0, 0, view.getMeasuredWidth(), mStickyHeaderHeight = view.getMeasuredHeight()); | |
| } | |
| public interface StickyHeaderInterface { | |
| /** | |
| * This method gets called by {@link StickHeaderItemDecoration} to fetch the position of the header item in the adapter | |
| * that is used for (represents) item at specified position. | |
| * @param itemPosition int. Adapter's position of the item for which to do the search of the position of the header item. | |
| * @return int. Position of the header item in the adapter. | |
| */ | |
| int getHeaderPositionForItem(int itemPosition); | |
| /** | |
| * This method gets called by {@link StickHeaderItemDecoration} to get layout resource id for the header item at specified adapter's position. | |
| * @param headerPosition int. Position of the header item in the adapter. | |
| * @return int. Layout resource id. | |
| */ | |
| int getHeaderLayout(int headerPosition); | |
| /** | |
| * This method gets called by {@link StickHeaderItemDecoration} to setup the header View. | |
| * @param header View. Header to set the data on. | |
| * @param headerPosition int. Position of the header item in the adapter. | |
| */ | |
| void bindHeaderData(View header, int headerPosition); | |
| /** | |
| * This method gets called by {@link StickHeaderItemDecoration} to verify whether the item represents a header. | |
| * @param itemPosition int. | |
| * @return true, if item at the specified adapter's position represents a header. | |
| */ | |
| boolean isHeader(int itemPosition); | |
| } | |
| } |
| RecyclerView recyclerView = findViewById(R.id.recyclerView); | |
| SimpleRecyclerView adapter = new SimpleRecyclerView(); | |
| LinearLayoutManager layoutManager = new LinearLayoutManager(this); | |
| recyclerView.setAdapter(adapter); | |
| recyclerView.setLayoutManager(layoutManager); | |
| recyclerView.addItemDecoration(new StickHeaderItemDecoration(adapter)); |
You can't interact with ItemDecorators
How to handle the pagination?
this stick header very helpful me, thank you .
Thanks for this
This is helpful, Thank you
It's working!
@smuyyh what is paint???
https://github.com/smuyyh/StickyHeaderRecyclerView
This allows sticky headers to be implemented through viewholder
If you scroll immediately after setting response then it is crashing
java.lang.IndexOutOfBoundsException: Index: 7, Size: 7
at java.util.ArrayList.get(ArrayList.java:437)
at com.test.ui.alerts.adapters.HeaderChildAdapter.isHeader(HeaderChildAdapter.kt:56)
have you handle this crash?
I am not able to get click event on the header. is it possible ? As i have a image view in the header view i need to get the click event.
You can use this approach if it suits your requirements it can support clicks aswell for sticky headers, https://gist.github.com/preetham1316/d21be9e6987be601a7d5507081c127a8
The header will duplicate when the view overlay. How to solve it?
https://stackoverflow.com/questions/76903052/android-recyclerview-sticky-header-alpha-view
I am not able to get click event on the header. is it possible ?
As i have a image view in the header view i need to get the click event.