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版本号不久前已经正式公布了,对于我 ...
随机推荐
- python学习之路---day09
函数案例: return 可以终止函数后面的调用 def abc() print("1") print("2") print("3") pr ...
- C++_基础1-基本数据类型
面向对象(OOP)的本质是设计并扩展自己的数据类型.设计自己的数据类型就是让类型与数据匹配. 如果正确做到这一点,就会发现以后使用数据会容易很多.然而创建自己的类型之前,必须了解并理解C++内置类型. ...
- Kibana6.x.x源码分析--如何自定义savedObjectType对象
上篇说到了如何使用kibana自带的savedObjectType对象,现在我们来自定义一个自己的savedObjectType. 下面的截图是我自己模仿写的保存对象,以及如何在kibana插件中注册 ...
- P4578 [FJOI2018]所罗门王的宝藏
传送门 考虑一个位置答案传递性,如果某个位置的红宝石转动确定了,那么会引起连锁反应: 如图,绿色的转动确定了,那么那两个蓝色的转动也确定了 自己手玩一下,发现如果有解那么随便找一个开始然后一路玩下去最 ...
- HTML嵌套php
1. <?php echo 'if you want to serve XHTML or XML documents, do it like this'; ?> 2. <scri ...
- ThinkPHP vendor 方法导入第三方类库
ThinkPHP 3.2 vendor()方法的深入研究及Phpqrcode的正确扩展 ThinkPHP vendor 方法导入第三方类库 第三方类库 第三方类库指除了 ThinkPHP 框架.应用项 ...
- 【研究】Struts2-052漏洞
漏洞描述: CVE-2017-9805 2017年9月5日,Apache Struts官方发布最新的安全公告称,Apache Struts 2.5.x的REST插件存在远程代码执行高危漏洞,漏洞编号为 ...
- PIE SDK矢量数据空间索引的创建
1. 功能简介 空间索引的使用便于数据的查询:所以在创建矢量数据的时候创建空间索引,下面对矢量数据如何创建空间索引进行功能介绍. 2. 功能实现说明 2.1. 实现思路及原理说明 第一步 创建矢量要素 ...
- Python+Selenium定位元素的方法
Python+Selenium有以下八种定位元素的方法: 1. find_element_by_id() eg: find_element_by_id("kw") 2. find_ ...
- harbor 仓库搭建
一,介绍 Harbor是一个用于存储Docker镜像的企业级Registry服务. Registry是Dcoker官方的一个私有仓库镜像,可以将本地的镜像打标签进行标记然后push到以Registry ...