【Android视图效果】分组列表实现吸顶效果
2019-02-12 本文已影响613人
欢子3824
效果图
20190212_142252.gif分析
先来分析一下,可以看到这是一个按月份分组的2行图片列表,列表顶部一个悬浮栏,会随着列表滑动而刷新,点击顶部栏,弹出了一个筛选框。
思路
1.列表部分
可以用RecyclerView
+GridLayoutManager
,月份的标题栏可以使用多布局
首先是主体item的布局
<?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>
然后是月份标题的布局
<?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
方法。
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方法这里就不贴了
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
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);
}
}
}
}
}
2.顶部栏部分
这里可以使用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);
}
}
3.点击顶部栏弹窗
这里就偷个懒,不贴代码了。