前面說了RecyclerView
的ItemDecoration
,這裏咱們用它來實現個吸頂效果php
先來分析一下,能夠看到這是一個按月份分組的2行圖片列表,列表頂部一個懸浮欄,會隨着列表滑動而刷新,點擊頂部欄,彈出了一個篩選框。java
能夠用RecyclerView
+GridLayoutManager
,月份的標題欄可使用多佈局android
首先是主體item的佈局git
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/cffffff" app:cardCornerRadius="4dp">
<android.support.constraint.ConstraintLayout android:layout_width="match_parent" android:layout_height="wrap_content">
<ImageView android:id="@+id/iv_pictrue" android:layout_width="match_parent" android:layout_height="0dp" app:layout_constraintDimensionRatio="1.78:1" />
<TextView android:id="@+id/tv_pictrue_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:textColor="@color/c151619" android:textSize="16sp" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toBottomOf="@id/iv_pictrue" tools:text="長沙會議圖集(210)" />
<TextView android:id="@+id/tv_pictrue_time" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="2dp" android:layout_marginBottom="10dp" tools:text="2018-11-10" android:textColor="@color/c969696" android:textSize="16sp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toBottomOf="@id/tv_pictrue_title" />
</android.support.constraint.ConstraintLayout>
</android.support.v7.widget.CardView>
複製代碼
而後是月份標題的佈局github
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_vertical" android:orientation="horizontal" android:paddingTop="15dp" android:paddingBottom="15dp">
<TextView android:layout_width="0dp" android:layout_height="1dp" android:layout_marginLeft="15dp" android:layout_marginRight="10dp" android:layout_weight="1" android:background="@color/cbbbfc2" />
<TextView android:id="@+id/tv_picture_month" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="2018年10月" android:textColor="@color/c969696" android:textSize="16sp" />
<TextView android:layout_width="0dp" android:layout_height="1dp" android:layout_marginLeft="10dp" android:layout_marginRight="15dp" android:layout_weight="1" android:background="@color/cbbbfc2" />
</LinearLayout>
複製代碼
PictureAdapter
這裏使用了 BaseRecyclerViewAdapterHelper,須要繼承BaseMultiItemQuickAdapter
,關於adapter多佈局的使用,篇幅所限,這裏再也不細述。緩存
public class PictureAdapter extends BaseMultiItemQuickAdapter<PictureModel, BaseViewHolder> {
public PictureAdapter(@Nullable List<PictureModel> data) {
super(data);
addItemType(PictureModel.PICTURE_CONTENT, R.layout.item_pictures);
addItemType(PictureModel.PICTURE_TITLE, R.layout.item_picture_month);
}
@Override
protected void convert(BaseViewHolder helper, PictureModel item) {
if (helper.getItemViewType() == PictureModel.PICTURE_CONTENT) {
//標題/數量
helper.setText(R.id.tv_pictrue_title, item.getTitle() + "(" + item.getPicture_count() + ")");
//時間
helper.setText(R.id.tv_pictrue_time, item.getDate());
//封面圖
GlideUtils.loadImg(mContext, item.getCover_image(), (ImageView) helper.getView(R.id.iv_pictrue));
} else if (helper.getItemViewType() == PictureModel.PICTURE_TITLE) {
helper.setText(R.id.tv_picture_month, item.getDate());
}
}
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
FullSpanUtil.onAttachedToRecyclerView(recyclerView, this, PictureModel.PICTURE_TITLE);
}
@Override
public void onViewDetachedFromWindow(@NonNull BaseViewHolder holder) {
super.onViewDetachedFromWindow(holder);
FullSpanUtil.onViewAttachedToWindow(holder, this, PictureModel.PICTURE_TITLE);
}
}
複製代碼
其中,因爲月份的標題須要佔滿一行,須要重寫onAttachedToRecyclerView
和onViewDetachedFromWindow
方法。app
public class FullSpanUtil {
public static void onAttachedToRecyclerView(RecyclerView recyclerView, final RecyclerView.Adapter adapter, final int pinnedHeaderType) {
// 若是是網格佈局,這裏處理標籤的佈局佔滿一行
final RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
if (layoutManager instanceof GridLayoutManager) {
final GridLayoutManager gridLayoutManager = (GridLayoutManager) layoutManager;
final GridLayoutManager.SpanSizeLookup oldSizeLookup = gridLayoutManager.getSpanSizeLookup();
gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
if (adapter.getItemViewType(position) == pinnedHeaderType) {
return gridLayoutManager.getSpanCount();
}
if (oldSizeLookup != null) {
return oldSizeLookup.getSpanSize(position);
}
return 1;
}
});
}
}
public static void onViewAttachedToWindow(RecyclerView.ViewHolder holder, RecyclerView.Adapter adapter, int pinnedHeaderType) {
// 若是是瀑布流佈局,這裏處理標籤的佈局佔滿一行
final ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
if (lp instanceof StaggeredGridLayoutManager.LayoutParams) {
final StaggeredGridLayoutManager.LayoutParams slp = (StaggeredGridLayoutManager.LayoutParams) lp;
slp.setFullSpan(adapter.getItemViewType(holder.getLayoutPosition()) == pinnedHeaderType);
}
}
}
複製代碼
PictureModel
須要繼承MultiItemEntity
,而後重寫getItemType
方法,adapter
便可經過model
的type
來判斷該使用哪一個佈局。 注:get和set方法這裏就不貼了ide
public class PictureModel implements MultiItemEntity {
public static final int PICTURE_TITLE = 1;
public static final int PICTURE_CONTENT = 0;
private int type;
private String id;
private String title;
private String date_time;
private String create_time;
private String picture_count;
private String status;
private String cover_image;
private String date;
public PictureModel(int type) {
this.type = type;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
@Override
public int getItemType() {
return type;
}
}
複製代碼
最後,是在Activity
使用佈局
pictureAdapter = new PictureAdapter(null);
rvPictrues.setLayoutManager(new GridLayoutManager(context, 2));
SpaceDecoration spaceDecoration = new SpaceDecoration(dp2px(context, 10));
spaceDecoration.setPaddingStart(false);
rvPictrues.addItemDecoration(spaceDecoration);
rvPictrues.setAdapter(pictureAdapter);
pictureAdapter.bindToRecyclerView(rvPictrues);
複製代碼
/** * dp轉px * * @param context * @param dpVal * @return */
public static int dp2px(Context context, float dpVal) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpVal,
context.getResources().getDisplayMetrics());
}
複製代碼
SpaceDecoration
post
public class SpaceDecoration extends RecyclerView.ItemDecoration {
private int space;
private int headerCount = -1;
private int footerCount = Integer.MAX_VALUE;
private boolean mPaddingEdgeSide = true;
private boolean mPaddingStart = true;
private boolean mPaddingHeaderFooter = false;
private ColorDrawable mColorDrawable;
private boolean mDrawLastItem = true;
private boolean mDrawHeaderFooter = false;
public SpaceDecoration(int space) {
this.mColorDrawable = new ColorDrawable(Color.parseColor("#e7e7e7"));
this.space = space;
}
public SpaceDecoration(int space, int color) {
this.mColorDrawable = new ColorDrawable(color);
this.space = space;
}
public void setPaddingEdgeSide(boolean mPaddingEdgeSide) {
this.mPaddingEdgeSide = mPaddingEdgeSide;
}
public void setPaddingStart(boolean mPaddingStart) {
this.mPaddingStart = mPaddingStart;
}
public void setPaddingHeaderFooter(boolean mPaddingHeaderFooter) {
this.mPaddingHeaderFooter = mPaddingHeaderFooter;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
int position = parent.getChildAdapterPosition(view);
int spanCount = 0;
int orientation = 0;
int spanIndex = 0;
int headerCount = 0, footerCount = 0;
if (parent.getAdapter() instanceof BaseQuickAdapter) {
headerCount = ((BaseQuickAdapter) parent.getAdapter()).getHeaderLayoutCount();
footerCount = ((BaseQuickAdapter) parent.getAdapter()).getFooterLayoutCount();
}
RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
if (layoutManager instanceof StaggeredGridLayoutManager) {
orientation = ((StaggeredGridLayoutManager) layoutManager).getOrientation();
spanCount = ((StaggeredGridLayoutManager) layoutManager).getSpanCount();
spanIndex = ((StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams()).getSpanIndex();
} else if (layoutManager instanceof GridLayoutManager) {
orientation = ((GridLayoutManager) layoutManager).getOrientation();
spanCount = ((GridLayoutManager) layoutManager).getSpanCount();
spanIndex = ((GridLayoutManager.LayoutParams) view.getLayoutParams()).getSpanIndex();
} else if (layoutManager instanceof LinearLayoutManager) {
orientation = ((LinearLayoutManager) layoutManager).getOrientation();
spanCount = 1;
spanIndex = 0;
}
/** * 普通Item的尺寸 */
if ((position >= headerCount && position < parent.getAdapter().getItemCount() - footerCount)) {
if (orientation == VERTICAL) {
float expectedWidth = (float) (parent.getWidth() - space * (spanCount + (mPaddingEdgeSide ? 1 : -1))) / spanCount;
float originWidth = (float) parent.getWidth() / spanCount;
float expectedX = (mPaddingEdgeSide ? space : 0) + (expectedWidth + space) * spanIndex;
float originX = originWidth * spanIndex;
outRect.left = (int) (expectedX - originX);
outRect.right = (int) (originWidth - outRect.left - expectedWidth);
if (position - headerCount < spanCount && mPaddingStart) {
outRect.top = space;
}
outRect.bottom = space;
return;
} else {
float expectedHeight = (float) (parent.getHeight() - space * (spanCount + (mPaddingEdgeSide ? 1 : -1))) / spanCount;
float originHeight = (float) parent.getHeight() / spanCount;
float expectedY = (mPaddingEdgeSide ? space : 0) + (expectedHeight + space) * spanIndex;
float originY = originHeight * spanIndex;
outRect.bottom = (int) (expectedY - originY);
outRect.top = (int) (originHeight - outRect.bottom - expectedHeight);
if (position - headerCount < spanCount && mPaddingStart) {
outRect.left = space;
}
outRect.right = space;
return;
}
} else if (mPaddingHeaderFooter) {
if (orientation == VERTICAL) {
outRect.right = outRect.left = mPaddingEdgeSide ? space : 0;
outRect.top = mPaddingStart ? space : 0;
} else {
outRect.top = outRect.bottom = mPaddingEdgeSide ? space : 0;
outRect.left = mPaddingStart ? space : 0;
}
}
}
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
if (parent.getAdapter() == null) {
return;
}
int orientation = 0;
int headerCount = 0, footerCount = 0, dataCount;
if (parent.getAdapter() instanceof BaseQuickAdapter) {
headerCount = ((BaseQuickAdapter) parent.getAdapter()).getHeaderLayoutCount();
footerCount = ((BaseQuickAdapter) parent.getAdapter()).getFooterLayoutCount();
dataCount = parent.getAdapter().getItemCount();
} else {
dataCount = parent.getAdapter().getItemCount();
}
int dataStartPosition = headerCount;
int dataEndPosition = headerCount + dataCount;
RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
if (layoutManager instanceof StaggeredGridLayoutManager) {
orientation = ((StaggeredGridLayoutManager) layoutManager).getOrientation();
} else if (layoutManager instanceof GridLayoutManager) {
orientation = ((GridLayoutManager) layoutManager).getOrientation();
} else if (layoutManager instanceof LinearLayoutManager) {
orientation = ((LinearLayoutManager) layoutManager).getOrientation();
}
int start, end;
if (orientation == OrientationHelper.VERTICAL) {
start = parent.getPaddingLeft();
end = parent.getWidth() - parent.getPaddingRight();
} else {
start = parent.getPaddingTop();
end = parent.getHeight() - parent.getPaddingBottom();
}
int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
View child = parent.getChildAt(i);
int position = parent.getChildAdapterPosition(child);
if (position >= dataStartPosition && position < dataEndPosition - 1//數據項除了最後一項
|| (position == dataEndPosition - 1 && mDrawLastItem)//數據項最後一項
|| (!(position >= dataStartPosition && position < dataEndPosition) && mDrawHeaderFooter)//header&footer且可繪製
) {
if (orientation == OrientationHelper.VERTICAL) {
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
int top = child.getBottom() + params.bottomMargin;
int bottom = top;
mColorDrawable.setBounds(start, top, end, bottom);
mColorDrawable.draw(c);
} else {
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
int left = child.getRight() + params.rightMargin;
int right = left;
mColorDrawable.setBounds(left, start, right, end);
mColorDrawable.draw(c);
}
}
}
}
}
複製代碼
這裏可使用ItemDecoration
,難點在於如何設置點擊點擊事件。感謝做者,提供了一種新的思路 StickyItemDecoration,這裏只說如何使用,原理閱讀做者源碼便可。 按照這個思路,咱們能夠將頭部佈局單獨出來,這樣的話,處理點擊事件就很簡單。 activity佈局
<RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView android:id="@+id/rv_pictrues" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/cf7f8fa" android:nestedScrollingEnabled="false" />
<com.leda.yunke.widget.sticky.StickyHeadContainer android:id="@+id/shc_pictrues" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/cffffff">
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_horizontal" android:orientation="vertical">
<TextView android:id="@+id/tv_picture_time" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="8dp" android:layout_marginBottom="8dp" android:drawableRight="@mipmap/unfold" android:drawablePadding="10dp" android:gravity="center" android:text="2018年11月" android:textColor="@color/c969696" android:textSize="16sp" />
<TextView style="@style/line_f3f3f3" />
</LinearLayout>
</com.leda.yunke.widget.sticky.StickyHeadContainer>
</RelativeLayout>
複製代碼
StickyHeadContainer
public class StickyHeadContainer extends ViewGroup {
private int mOffset;
private int mLastOffset = Integer.MIN_VALUE;
private int mLastStickyHeadPosition = Integer.MIN_VALUE;
private int mLeft;
private int mRight;
private int mTop;
private int mBottom;
private DataCallback mDataCallback;
public StickyHeadContainer(Context context) {
this(context, null);
}
public StickyHeadContainer(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public StickyHeadContainer(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO: 2017/1/9 屏蔽點擊事件
}
});
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int desireHeight;
int desireWidth;
int count = getChildCount();
if (count != 1) {
throw new IllegalArgumentException("只容許容器添加1個子View!");
}
final View child = getChildAt(0);
// 測量子元素並考慮外邊距
measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
// 獲取子元素的佈局參數
final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
// 計算子元素寬度,取子控件最大寬度
desireWidth = child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;
// 計算子元素高度
desireHeight = child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;
// 考慮父容器內邊距
desireWidth += getPaddingLeft() + getPaddingRight();
desireHeight += getPaddingTop() + getPaddingBottom();
// 嘗試比較建議最小值和指望值的大小並取大值
desireWidth = Math.max(desireWidth, getSuggestedMinimumWidth());
desireHeight = Math.max(desireHeight, getSuggestedMinimumHeight());
// 設置最終測量值
setMeasuredDimension(resolveSize(desireWidth, widthMeasureSpec), resolveSize(desireHeight, heightMeasureSpec));
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
final View child = getChildAt(0);
MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
final int paddingLeft = getPaddingLeft();
final int paddingTop = getPaddingTop();
mLeft = paddingLeft + lp.leftMargin;
mRight = child.getMeasuredWidth() + mLeft;
mTop = paddingTop + lp.topMargin + mOffset;
mBottom = child.getMeasuredHeight() + mTop;
child.layout(mLeft, mTop, mRight, mBottom);
}
// 生成默認的佈局參數
@Override
protected LayoutParams generateDefaultLayoutParams() {
return super.generateDefaultLayoutParams();
}
// 生成佈局參數,將佈局參數包裝成咱們的
@Override
protected LayoutParams generateLayoutParams(LayoutParams p) {
return new MarginLayoutParams(p);
}
// 生成佈局參數,從屬性配置中生成咱們的佈局參數
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new MarginLayoutParams(getContext(), attrs);
}
// 查當前佈局參數是不是咱們定義的類型這在code聲明佈局參數時經常用到
@Override
protected boolean checkLayoutParams(LayoutParams p) {
return p instanceof MarginLayoutParams;
}
public void scrollChild(int offset) {
if (mLastOffset != offset) {
mOffset = offset;
ViewCompat.offsetTopAndBottom(getChildAt(0), mOffset - mLastOffset);
}
mLastOffset = mOffset;
}
protected int getChildHeight() {
return getChildAt(0).getHeight();
}
protected void onDataChange(int stickyHeadPosition) {
if (mDataCallback != null && mLastStickyHeadPosition != stickyHeadPosition) {
mDataCallback.onDataChange(stickyHeadPosition);
}
mLastStickyHeadPosition = stickyHeadPosition;
}
public void reset() {
mLastStickyHeadPosition = Integer.MIN_VALUE;
}
public interface DataCallback {
void onDataChange(int pos);
}
public void setDataCallback(DataCallback dataCallback) {
mDataCallback = dataCallback;
}
}
複製代碼
在activity
中完整使用
StickyItemDecoration stickyItemDecoration = new StickyItemDecoration(shcPictrues, PictureModel.PICTURE_TITLE);
stickyItemDecoration.setOnStickyChangeListener(new OnStickyChangeListener() {
@Override
public void onScrollable(int offset) {
//可見時
shcPictrues.scrollChild(offset);
shcPictrues.setVisibility(View.VISIBLE);
}
@Override
public void onInVisible() {
//不可見時
shcPictrues.reset();
shcPictrues.setVisibility(View.INVISIBLE);
}
});
shcPictrues.setDataCallback(new StickyHeadContainer.DataCallback() {
@Override
public void onDataChange(int pos) {
//數據更新
List<PictureModel> listModels = pictureAdapter.getData();
if (listModels.size() > pos) {
tvPictureTime.setText(listModels.get(pos).getDate());
}
}
});
//添加至rv
rvPictrues.addItemDecoration(stickyItemDecoration);
pictureAdapter = new PictureAdapter(null);
rvPictrues.setLayoutManager(new GridLayoutManager(context, 2));
rvPictrues.addItemDecoration(stickyItemDecoration);
SpaceDecoration spaceDecoration = new SpaceDecoration(DensityUtils.dp2px(context, 10));
spaceDecoration.setPaddingStart(false);
rvPictrues.addItemDecoration(spaceDecoration);
rvPictrues.setAdapter(pictureAdapter);
pictureAdapter.bindToRecyclerView(rvPictrues);
複製代碼
StickyItemDecoration
public class StickyItemDecoration extends RecyclerView.ItemDecoration {
private int mStickyHeadType;
private int mFirstVisiblePosition;
// private int mFirstCompletelyVisiblePosition;
private int mStickyHeadPosition;
private int[] mInto;
private RecyclerView.Adapter mAdapter;
private StickyHeadContainer mStickyHeadContainer;
private boolean mEnableStickyHead = true;
private OnStickyChangeListener mOnStickyChangeListener;
public void setOnStickyChangeListener(OnStickyChangeListener onStickyChangeListener){
this.mOnStickyChangeListener = onStickyChangeListener;
}
public StickyItemDecoration(StickyHeadContainer stickyHeadContainer, int stickyHeadType) {
mStickyHeadContainer = stickyHeadContainer;
mStickyHeadType = stickyHeadType;
}
// 當咱們調用mRecyclerView.addItemDecoration()方法添加decoration的時候,RecyclerView在繪製的時候,去會繪製decorator,即調用該類的onDraw和onDrawOver方法,
// 1.onDraw方法先於drawChildren
// 2.onDrawOver在drawChildren以後,通常咱們選擇複寫其中一個便可。
// 3.getItemOffsets 能夠經過outRect.set()爲每一個Item設置必定的偏移量,主要用於繪製Decorator。
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDraw(c, parent, state);
checkCache(parent);
if (mAdapter == null) {
// checkCache的話RecyclerView未設置以前mAdapter爲空
return;
}
calculateStickyHeadPosition(parent);
if (mEnableStickyHead /*&& mFirstCompletelyVisiblePosition > mStickyHeadPosition*/ && mFirstVisiblePosition >= mStickyHeadPosition && mStickyHeadPosition != -1) {
View belowView = parent.findChildViewUnder(c.getWidth() / 2, mStickyHeadContainer.getChildHeight() + 0.01f);
mStickyHeadContainer.onDataChange(mStickyHeadPosition);
int offset;
if (isStickyHead(parent, belowView) && belowView.getTop() > 0) {
offset = belowView.getTop() - mStickyHeadContainer.getChildHeight();
} else {
offset = 0;
}
if (mOnStickyChangeListener!=null){
mOnStickyChangeListener.onScrollable(offset);
}
} else {
if (mOnStickyChangeListener!=null){
mOnStickyChangeListener.onInVisible();
}
}
}
public void enableStickyHead(boolean enableStickyHead) {
mEnableStickyHead = enableStickyHead;
if (!mEnableStickyHead) {
mStickyHeadContainer.setVisibility(View.INVISIBLE);
}
}
private void calculateStickyHeadPosition(RecyclerView parent) {
final RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
// mFirstCompletelyVisiblePosition = findFirstCompletelyVisiblePosition(layoutManager);
// 獲取第一個可見的item位置
mFirstVisiblePosition = findFirstVisiblePosition(layoutManager);
// 獲取標籤的位置,
int stickyHeadPosition = findStickyHeadPosition(mFirstVisiblePosition);
if (stickyHeadPosition >= 0 && mStickyHeadPosition != stickyHeadPosition) {
// 標籤位置有效而且和緩存的位置不一樣
mStickyHeadPosition = stickyHeadPosition;
}
}
/** * 從傳入位置遞減找出標籤的位置 * * @param formPosition * @return */
private int findStickyHeadPosition(int formPosition) {
for (int position = formPosition; position >= 0; position--) {
// 位置遞減,只要查到位置是標籤,當即返回此位置
final int type = mAdapter.getItemViewType(position);
if (isStickyHeadType(type)) {
return position;
}
}
return -1;
}
/** * 經過適配器告知類型是否爲標籤 * * @param type * @return */
private boolean isStickyHeadType(int type) {
return mStickyHeadType == type;
}
/** * 找出第一個可見的Item的位置 * * @param layoutManager * @return */
private int findFirstVisiblePosition(RecyclerView.LayoutManager layoutManager) {
int firstVisiblePosition = 0;
if (layoutManager instanceof GridLayoutManager) {
firstVisiblePosition = ((GridLayoutManager) layoutManager).findFirstVisibleItemPosition();
} else if (layoutManager instanceof LinearLayoutManager) {
firstVisiblePosition = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition();
} else if (layoutManager instanceof StaggeredGridLayoutManager) {
mInto = new int[((StaggeredGridLayoutManager) layoutManager).getSpanCount()];
((StaggeredGridLayoutManager) layoutManager).findFirstVisibleItemPositions(mInto);
firstVisiblePosition = Integer.MAX_VALUE;
for (int pos : mInto) {
firstVisiblePosition = Math.min(pos, firstVisiblePosition);
}
}
return firstVisiblePosition;
}
/** * 找出第一個徹底可見的Item的位置 * * @param layoutManager * @return */
private int findFirstCompletelyVisiblePosition(RecyclerView.LayoutManager layoutManager) {
int firstVisiblePosition = 0;
if (layoutManager instanceof GridLayoutManager) {
firstVisiblePosition = ((GridLayoutManager) layoutManager).findFirstCompletelyVisibleItemPosition();
} else if (layoutManager instanceof LinearLayoutManager) {
firstVisiblePosition = ((LinearLayoutManager) layoutManager).findFirstCompletelyVisibleItemPosition();
} else if (layoutManager instanceof StaggeredGridLayoutManager) {
mInto = new int[((StaggeredGridLayoutManager) layoutManager).getSpanCount()];
((StaggeredGridLayoutManager) layoutManager).findFirstCompletelyVisibleItemPositions(mInto);
firstVisiblePosition = Integer.MAX_VALUE;
for (int pos : mInto) {
firstVisiblePosition = Math.min(pos, firstVisiblePosition);
}
}
return firstVisiblePosition;
}
/** * 檢查緩存 * * @param parent */
private void checkCache(final RecyclerView parent) {
final RecyclerView.Adapter adapter = parent.getAdapter();
if (mAdapter != adapter) {
mAdapter = adapter;
// 適配器爲null或者不一樣,清空緩存
mStickyHeadPosition = -1;
mAdapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
@Override
public void onChanged() {
reset();
}
@Override
public void onItemRangeChanged(int positionStart, int itemCount) {
reset();
}
@Override
public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {
reset();
}
@Override
public void onItemRangeInserted(int positionStart, int itemCount) {
reset();
}
@Override
public void onItemRangeRemoved(int positionStart, int itemCount) {
reset();
}
@Override
public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
reset();
}
});
}
}
private void reset() {
mStickyHeadContainer.reset();
}
/** * 查找到view對應的位置從而判斷出是否標籤類型 * * @param parent * @param view * @return */
private boolean isStickyHead(RecyclerView parent, View view) {
final int position = parent.getChildAdapterPosition(view);
if (position == RecyclerView.NO_POSITION) {
return false;
}
final int type = mAdapter.getItemViewType(position);
return isStickyHeadType(type);
}
}
複製代碼
這裏就偷個懶,不貼代碼了。
pictureAdapter
便可。