Created
April 28, 2019 10:51
-
-
Save shishirthedev/a4ee4a6f51bccd786465e85d85026c49 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| public class SnStickyHeaderItemDecoration extends RecyclerView.ItemDecoration { | |
| private SnStickyListener mListener; | |
| private Integer mHeaderHeight; | |
| public SnStickyHeaderItemDecoration(SnStickyListener listener) { | |
| this.mListener = listener; | |
| } | |
| @Override | |
| public void onDrawOver(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull 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 = mHeaderHeight - 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(), mHeaderHeight = view.getMeasuredHeight()); | |
| } | |
| } | |
| ///////////////////////////////////////////////////////////////////////////////////////////// | |
| public interface SnStickyListener { | |
| Integer getHeaderPositionForItem(Integer itemPosition); | |
| Integer getHeaderLayout(Integer headerPosition); | |
| void bindHeaderData(View header, Integer headerPosition); | |
| Boolean isHeader(Integer itemPosition); | |
| } | |
| /////////////////////////////////////////////////////////////////////////////////////////////// | |
| public class DepositLogsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements SnStickyListener { | |
| private Context context; | |
| static final int TYPE_HEADER = 0; | |
| static final int TYPE_ITEM = 1; | |
| public DepositLogsAdapter(Context context) { | |
| this.context = context; | |
| } | |
| @Override | |
| public int getItemViewType(int position) { | |
| return position % 5 == 0 ? TYPE_HEADER : TYPE_ITEM; | |
| } | |
| @Override | |
| public Integer getHeaderPositionForItem(Integer itemPosition) { | |
| Integer headerPosition = 0; | |
| for (Integer i = itemPosition; i > 0; i--) { | |
| if (isHeader(i)) { | |
| headerPosition = i; | |
| return headerPosition; | |
| } | |
| } | |
| return headerPosition; | |
| } | |
| @Override | |
| public Integer getHeaderLayout(Integer headerPosition) { | |
| return R.layout.deposit_log_header_view; | |
| } | |
| @Override | |
| public void bindHeaderData(View headerView, Integer headerPosition) { | |
| // bind data to header view..... | |
| } | |
| @Override | |
| public Boolean isHeader(Integer itemPosition) { | |
| return itemPosition % 5 == 0; | |
| } | |
| class ItemView extends RecyclerView.ViewHolder { | |
| ItemView(View itemView) { | |
| super(itemView); | |
| } | |
| } | |
| @NonNull | |
| @Override | |
| public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { | |
| if (viewType == TYPE_ITEM) { | |
| View view = LayoutInflater.from(context).inflate(R.layout.deposit_log_item_view, parent, false); | |
| return new ItemView(view); | |
| } else { | |
| View view = LayoutInflater.from(context).inflate(R.layout.deposit_log_header_view, parent, false); | |
| return new ItemView(view); | |
| } | |
| } | |
| @Override | |
| public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { | |
| } | |
| @Override | |
| public int getItemCount() { | |
| return 25; | |
| } | |
| } | |
| // END |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment