顶部粘性的列表
先看效果 源码 Paste_Image.png 002.gif 为什么写这个控件? 之前有朋友问我,会不会手写这种效果,不是借助于第三方,卧槽,懵逼了。。。 网上搜罗了几个这种实现效果,感觉代码写的比较复杂 或者 实现效果不佳,还是自己动手实现一下吧。 首先需要一个 自定义接口 OnStickyViewChangeListener <pre> package org.alex.sectionrecyclerlayout; import android.view.View; /** * 作者:Alex * 时间:2016/11/14 14:31 * 简述:只要你的adapter实现了这接口,基本上就能做到这种效果了,自觉思路挺好的 */ public interface OnStickyViewChangeListener { int none = -99; int title = 1; int item = 2; int getStickyViewType(int position); int getHeadViewCount(); /\*\* \* @param position \* 在 RecyclerView 中 的下标 \*/ void onStickyViewTypeChange(View view, int position); } </pre> 组合一个控件,将 stickView 和 RecyclerView 包裹起来 <pre> package org.alex.sectionrecyclerlayout; import android.content.Context; import android.content.res.TypedArray; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.OrientationHelper; import android.support.v7.widget.RecyclerView; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; import android.widget.RelativeLayout; /** * 作者:Alex * 时间:2016/11/14 11:22 * 简述: * * @link */ public class StickyRecyclerLayout extends RelativeLayout { private RecyclerView recyclerView; private View stickyView; private LinearLayoutManager linearLayoutManager; private int stickyViewHeight; private OnStickyViewChangeListener onStickyViewChangeListener; private int currItemViewType; public StickyRecyclerLayout(Context context, AttributeSet attrs) { super(context, attrs); initView(context, attrs); } private void initView(Context context, AttributeSet attrs) { currItemViewType = OnStickyViewChangeListener.none; recyclerView = new RecyclerView(context); RelativeLayout.LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); recyclerView.setLayoutParams(params); linearLayoutManager = new LinearLayoutManager(context); linearLayoutManager.setOrientation(OrientationHelper.VERTICAL); recyclerView.setLayoutManager(linearLayoutManager); recyclerView.addOnScrollListener(new MyOnScrollListener()); addView(recyclerView); TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.StickyRecyclerLayout); int layoutId = typedArray.getResourceId(R.styleable.StickyRecyclerLayout_srl_sticky_view_layoutRes, -1); if (layoutId != -1) { stickyView = LayoutInflater.from(context).inflate(layoutId, null); addView(stickyView); } typedArray.recycle(); } public RecyclerView getRecyclerView() { return recyclerView; } private final class MyOnScrollListener extends RecyclerView.OnScrollListener { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); if (stickyView == null) { return; } stickyViewHeight = stickyView.getMeasuredHeight(); onStickyViewChangeListener = (onStickyViewChangeListener == null) ? (OnStickyViewChangeListener) recyclerView.getAdapter() : onStickyViewChangeListener; int headViewCount = onStickyViewChangeListener.getHeadViewCount(); int firstVisibleItemPosition = linearLayoutManager.findFirstVisibleItemPosition(); //LogUtil.e("firstVisibleItemPosition == " + firstVisibleItemPosition); /\*参照物的 视图 \*/ View referenceView = linearLayoutManager.findViewByPosition(firstVisibleItemPosition + 1); /\*TODO:参照物的 视图 类型 \* \* 如果 你用到了 https://github.com/CymChad/BaseRecyclerViewAdapterHelper \* 同时使用了 adapter.addHeaderView(headView); \* int referenceItemViewType = onStickyViewChangeListener.getStickyViewType(firstVisibleItemPosition); \* \* 否则 \* int referenceItemViewType = onStickyViewChangeListener.getStickyViewType(firstVisibleItemPosition + 1 ); \* \*/ int referenceItemViewType = onStickyViewChangeListener.getStickyViewType(firstVisibleItemPosition + 1); if (firstVisibleItemPosition < headViewCount) { stickyView.setVisibility(View.GONE); } else { stickyView.setVisibility(View.VISIBLE); } //LogUtil.e(firstVisibleItemPosition + " referenceViewHeight = " + referenceView.getMeasuredHeight() + " nextViewTop = " + referenceView.getTop() + " viewType = " + ((referenceItemViewType == OnStickyViewChangeListener.title) ? "title" : "item")); if (referenceItemViewType == OnStickyViewChangeListener.title) { int nextViewTop = referenceView.getTop(); if (nextViewTop - stickyViewHeight < 0) { //LogUtil.e(firstVisibleItemPosition + " ######### nextViewTop - stickyViewHeight = " + (nextViewTop - stickyViewHeight)); stickyView.setTranslationY(nextViewTop - stickyViewHeight); } else { stickyView.setTranslationY(0); } } else { stickyView.setTranslationY(0); } /\* TODO: 响应 回调 \* 如果 你用到了 https://github.com/CymChad/BaseRecyclerViewAdapterHelper \* 同时使用了 adapter.addHeaderView(headView); \* int tmpPosition = (firstVisibleItemPosition >= 1) ? firstVisibleItemPosition - 1 : firstVisibleItemPosition; \* \* 否则 \* int tmpPosition = firstVisibleItemPosition; \* \*/ int tmpPosition = firstVisibleItemPosition; int tmpCurrentItemViewType = onStickyViewChangeListener.getStickyViewType(tmpPosition); if (currItemViewType != tmpCurrentItemViewType) { currItemViewType = tmpCurrentItemViewType; onStickyViewChangeListener.onStickyViewTypeChange(stickyView, tmpPosition); } } } } </pre> 如果 你用多种布局写的 headView 下面的不用看了 你用到了 BaseRecyclerViewAdapterHelper .addHeadView 需要单独处理一下,别问我为啥 <pre> /*TODO:参照物的 视图 类型 * * 如果 你用到了 https://github.com/CymChad/BaseRecyclerViewAdapterHelper * 同时使用了 adapter.addHeaderView(headView); * int referenceItemViewType = onStickyViewChangeListener.getStickyViewType(firstVisibleItemPosition); * * 否则 * int referenceItemViewType = onStickyViewChangeListener.getStickyViewType(firstVisibleItemPosition + 1 ); * */ /* TODO: 响应 回调 * 如果 你用到了 https://github.com/CymChad/BaseRecyclerViewAdapterHelper * 同时使用了 adapter.addHeaderView(headView); * int tmpPosition = (firstVisibleItemPosition >= 1) ? firstVisibleItemPosition - 1 : firstVisibleItemPosition; * * 否则 * int tmpPosition = firstVisibleItemPosition; * */ /*TODO: 设置 headview 个数 * 如果 你用到了 https://github.com/CymChad/BaseRecyclerViewAdapterHelper * 同时使用了 adapter.addHeaderView(headView); * adapter.setHeadViewCount(1); * */ </pre>