Android StickHeaderRecyclerView - 让recyclerview头部固定
介绍
在项目中有时会需要recyclerview滑动式时某个view滑出后会固定在头部显示,比较常用的比如手机联系人界面、地区选择界面等。 StickHeaderRecyclerView就是实现这个功能的。效果图:
这样的控件网上一抓一大把了,本控件的优点就是使用简单- lib简单 - 使用的语法也简单(之前下了2个类似开源项目,都是上万行代码。读起来麻烦、改起来麻烦就自己写了这个控件)
使用
只需要让你的adapter实现StickHeaderDecoration.StickHeaderInterface接口,方法boolean isStick(int position)中返回的值就标识当前位置的view是否需要固定。
同时需要让Adapter中的item不复用(如果怕影响性能也可以单独让需要固定的view不复用) 在adapter构造方法中setHasStableIds(true); 同时复写adapter的public long getItemId(int position) {return position;}
上代码
public class NormalAdapter extends RecyclerView.Adapter<NormalAdapter.InnerHolder> implements StickHeaderDecoration.StickHeaderInterface{ NormalAdapter(Activity activity, List<String> dates){
this.activity = activity;
this.dates = dates;
} @Override
public boolean isStick(int position) {
return position % == ;
} Activity activity;
private List<String> dates; @Override
public InnerHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View inflate = LayoutInflater.from(activity).inflate(R.layout.item, parent,
false);
return new InnerHolder(inflate);
} @Override
public void onBindViewHolder(InnerHolder holder, int position) {
if(isStick(position)){
holder.itemView.setBackgroundResource(R.color.colorAccent);
holder.tvText.setText(position / +"");
}else{
holder.itemView.setBackgroundResource(R.color.white);
holder.tvText.setText(dates.get(position));
}
} @Override
public int getItemCount() {
return dates.size();
} class InnerHolder extends RecyclerView.ViewHolder{
TextView tvText;
public InnerHolder(View itemView) {
super(itemView);
tvText = (TextView) itemView.findViewById(R.id.tvText);
}
}
}
activity代码
public class MainActivity extends Activity { private RecyclerView recycle;
private List<String> dates = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recycle = (RecyclerView) findViewById(R.id.recycle); for(int i=;i<;i++){
dates.add("date : "+i);
} recycle.setLayoutManager(new LinearLayoutManager(this));
recycle.setAdapter(new NormalAdapter(this, dates));
recycle.addItemDecoration(new StickHeaderDecoration(recycle));
} }
完成了
原理
先上核心类代码
public class StickHeaderDecoration extends RecyclerView.ItemDecoration { public interface StickHeaderInterface {
/**
* is this item need stick
* @param position now item position in the recyclerView
* @return true : need stick else not
*/
boolean isStick(int position);
} private RecyclerView recyclerView;
private RecyclerView.LayoutManager manager;
private RecyclerView.Adapter adapter;
private StickHeaderInterface stickHeaderInterface; /**
* 进行一些容错检查
*/
public StickHeaderDecoration(RecyclerView recyclerView) {
this.recyclerView = recyclerView;
this.manager = recyclerView.getLayoutManager();
this.adapter = recyclerView.getAdapter();
if (adapter == null) {
throw new RuntimeException("please set Decoration after set adapter");
} if (adapter instanceof StickHeaderInterface) {
stickHeaderInterface = (StickHeaderInterface) adapter;
return;
}
throw new RuntimeException("please make your adapter implements StickHeaderInterface");
} /**
* 绘制头部的stick view
*/
@Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDrawOver(c, parent, state);
View childAt = parent.getChildAt();
if (childAt == null)
return;
RecyclerView.ViewHolder childViewHolder = parent.getChildViewHolder(childAt);
int position = childViewHolder.getPosition();
for (int i = position; i >= ; i--) {
if (stickHeaderInterface.isStick(i)) {
int top = ;
if (position + < adapter.getItemCount()) {
if (stickHeaderInterface.isStick(position + )) {
View childNext = parent.getChildAt();
top = manager.getDecoratedTop(childNext) < ? : manager
.getDecoratedTop(childNext);
}
}
RecyclerView.ViewHolder inflate = recyclerView.getAdapter().createViewHolder(parent,
recyclerView.getAdapter().getItemViewType(i));
recyclerView.getAdapter().bindViewHolder(inflate, i);
int measureHeight = getMeasureHeight(inflate.itemView);
c.save();
if (top < inflate.itemView.getMeasuredHeight() && top > ) {
c.translate(, top - measureHeight);
}
inflate.itemView.draw(c);
c.restore();
return;
}
}
} /**
* 测量控件的高度
*
* @param header
*/
private int getMeasureHeight(View header) {
int widthSpec = View.MeasureSpec.makeMeasureSpec(recyclerView.getWidth(), View
.MeasureSpec.EXACTLY);
int heightSpec = View.MeasureSpec.makeMeasureSpec(, View.MeasureSpec.UNSPECIFIED);
header.measure(widthSpec, heightSpec);
header.layout(, , header.getMeasuredWidth(), header.getMeasuredHeight());
return header.getMeasuredHeight();
}
}
首先ItemDecoration是一个接口,通过RecyclerView的 recycle.addItemDecoration方法设置进去
其中只有6个方法其中3个过时了。我们这儿只需要对onDrawOver进行操作。
onDrawOver是当前RecyclerView绘制完毕后调用,可以其中进行绘制。我们的头部固定其实就是在这个方法中绘制进去的。
算法
1.这儿我们需要判断当前显示item的前面是否有需要固定的item(这儿取名为beforitem)如果有则绘制在顶部
2.我们还需要当第二个固定的item把前面的item慢慢顶上去的效果,这儿通过判断当前显示的第一个item的下一个item是否需要固定,如果需要则通过manager.getDecoratedTop(childNext)获取这个item距离顶部的距离然后通过计算把beforitem先上移动一定的距离。
基本原理就这样,相信代码更加有说服力,github 地址
https://github.com/LiuLinXin/StickHeaderRecyclerView-philer
待优化
头部view现在是通过ondraw绘制进去的,不能相应点击事件等。暂时没相处好的解决办法,希望有想法的朋友提示下。
Android StickHeaderRecyclerView - 让recyclerview头部固定的更多相关文章
- Android中当item数量超过一定大小RecyclerView高度固定
Android中当item数量超过一定大小时,将RecyclerView高度固定 方法1 直接通过LayoutParams来设定相应高度 ViewGroup.LayoutParams lp = rv. ...
- Android 高级编程 RecyclerView 控件的使用
RecyclerView 是Android 新添加的一个用来取代ListView的控件,它的灵活性与可替代性比listview更好. 看一下继承关系: ava.lang.Object ↳ and ...
- Android教程2020 - RecyclerView使用入门
本文介绍RecyclerView的使用入门.这里给出一种比较常见的使用方式. Android教程2020 - 系列总览 本文链接 想必读者朋友对列表的表现形式已经不再陌生.手机上有联系人列表,文件列表 ...
- 手机页面关于头部固定定位与input出现的问题
前些天写了一个页面,要求头部导航进行固定定位position:fixed.内容区域有输入框input.在大多数手机上都是显示正常的,可偏在一些低版本的手机却出现问题了. 把我给苦恼的不行. 问题:头部 ...
- Android学习之RecyclerView
RecyclerView是android-support-v7-21版本号中新增的一个Widget,官方介绍RecyclerView 是 ListView 的升级版本号,更加先进和灵活. 开发环境 - ...
- [Android] Android 让UI控件固定于底部的几种方法
Android 让UI控件固定于底部的几种方法1.采用linearlayout布局:android:layout_height="0dp" <!-- 这里不能设置fill_p ...
- Android Studio新建类头部注释和添加函数注释模板及快捷键
一,Android Studio新建类头部注释 是不是有时候看到这个很心烦 其实Studio中有设置修改这些注释模板的信息的功能 其实很简单,只需要两步: 1.打开Setting设置面板,找到File ...
- android开发学习 ------- RecyclerView多类型实例
实现RecyclerView多类型的实例:效果如下图所示 public class CarFragment extends Fragment{ private View view; private R ...
- Android最新组件RecyclerView,替代ListView
转载请注明出处:http://blog.csdn.net/allen315410/article/details/40379159 万众瞩目的android最新5.0版本号不久前已经正式公布了,对于我 ...
随机推荐
- Jquery 常用方法 及属性
Jquery 常用方法 及属性 jQuery 事件 鼠标事件 键盘事件 表单事件 文档/窗口事件 click keypress submit load dblclick keydown chang ...
- Codeforces Round #462 (Div. 2), problem: (C) A Twisty Movement (求可以转一次区间的不递增子序列元素只有1,2)
题目意思: 给长度为n(n<=2000)的数字串,数字只能为1或者2,可以将其中一段区间[l,r]翻转,求翻转后的最长非递减子序列长度. 题解:求出1的前缀和,2的后缀和,以及区间[i,j]的最 ...
- HDU - 1300 简单DP
题意:买珠子的方案有两种,要么单独买,价钱为该种类数量+10乘上相应价格,要么多个种类的数量相加再+10乘上相应最高贵的价格买 坑点:排序会WA,喵喵喵? 为什么连续取就是dp的可行方案?我猜的.. ...
- Codeforces - 631B 水题
注意到R和C只与最后一个状态有关 /*H E A D*/ struct node2{ int kind,las,val,pos; node2(){} node2(int k,int l,int v,i ...
- LightOJ - 1245 根号n暴力
打表或者画个图可以看出i>根号n时每个i的贡献值相差很小,可以利用公式优化(函数C) 但是注意不能一整段使用公式,否则复杂度还是会劣化到O(n)(显然对gongxian只能逐步递减) 网上看了不 ...
- opencv java小应用:比较两个图片的相似度
package com.company; import org.opencv.core.*; import org.opencv.imgcodecs.Imgcodecs; import org.ope ...
- 使用JWT来实现单点登录功能
出处: https://www.cnblogs.com/zexin/p/10389541.html 我们平时自己开发项目,分布式的结构时,访问量不大,但是又不想搭建redis服务器,这时我觉得jwt不 ...
- Java调度线程池ScheduleExecutorService
如果在一个ScheduleExecutorService中提交一个任务,这个任务的调度周期设置 的时间比任务本身执行的时间短的话会出现什么情况?也就是在线程调度时间已经到了 但是上次的任务还没有做完的 ...
- PIXI 根据点走地图(8)
先了解下数学公式例如: 图已知:a.b两点的坐标, c到a的距离d .求c点的坐标. 求 cy 可以根据d / a到b距离 = a到c垂直距离 / a 到 b的垂直距离. 首先求a到b的距离 ...
- 如何添加网页QQ在线组件
免费开通QQ推广服务 复制代码到你想要展示的位置 粘贴,完成.