先看效果 源码
为什么写这个控件?
之前有朋友问我,会不会手写这种效果,不是借助于第三方,卧槽,懵逼了。。。
网上搜罗了几个这种实现效果,感觉代码写的比较复杂 或者 实现效果不佳,还是自己动手实现一下吧。
首先需要一个 自定义接口 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>