先上图:
<方式一>添加外部Header实现方式
<方式二>绘制ItemDecoration实现方式
二者实现效果一样,下面分析下各自的实现逻辑。
添加外部Header实现方式
首先为每个RecyclerView的ItemView添加Header布局,这里简称为itemHeader。然后在RecyclerView的同级布局下添加Header布局,这里简称为mainHeader。列表数据展示时,只有位于同组的首个ItemView显示itemHeader,其余ItemView将itemHeader隐藏。当下一组的首个ItemView移动到位于mainHeader正下方时,计算该ItemView的位置来移动mainHeader;当该ItemView移动到顶部,即itemHeader位于mainHeader的位置时,mainHeader恢复原来位置。
Activity xml代码:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:toolbar="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
toolbar:popupTheme="@style/ToolbarPopupTheme">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="StickyHeader"
android:textColor="@color/colorWhite"
android:textSize="18sp"/>
</android.support.v7.widget.Toolbar>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/stickyheader_recyclerview"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<!-- Header布局 -->
<LinearLayout
android:id="@+id/sticky_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/color_material_light"
android:orientation="vertical">
<TextView
android:id="@+id/header_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="10dp"
android:paddingLeft="15dp"
android:paddingTop="10dp"
android:textColor="@color/colorTextContent"
android:textSize="14sp"
tools:text="2017年09月27日"/>
</LinearLayout>
</RelativeLayout>
</LinearLayout>
ItemView xml代码:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorWhite"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<!-- Header布局 -->
<LinearLayout
android:id="@+id/sticky_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/color_material_light"
android:orientation="vertical">
<TextView
android:id="@+id/header_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="10dp"
android:paddingLeft="15dp"
android:paddingTop="10dp"
android:textColor="@color/colorTextContent"
android:textSize="14sp"
tools:text="2017年09月27日"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingLeft="15dp">
<TextView
android:id="@+id/sticky_time_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/colorTextContent"
android:textSize="13sp"
android:textStyle="bold"
tools:text="18:00"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/sticky_content_textview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="15dp"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:layout_marginTop="15dp"
android:textColor="@color/colorTextContent"
android:textSize="16sp"
tools:text="这是内容"/>
<View
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:layout_marginLeft="15dp"
android:background="#E9E9E9"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
适配器Adapter代码:
...
public static final int FIRST_STICKY_VIEW = ;
public static final int HAS_STICKY_VIEW = ;
public static final int NONE_STICKY_VIEW = ;
...
@Override
public void onBindViewHolder(ViewHolder holder, int position)
{
StickyHeaderActivity.Model model = dataList.get(position);
holder.headerTv.setText(model.getHeader());
holder.timeTv.setText(model.getTime());
holder.contentTv.setText(model.getContent());
holder.itemView.setContentDescription(model.getHeader());
if (position == )
{
holder.headerLayout.setVisibility(View.VISIBLE);
holder.itemView.setTag(FIRST_STICKY_VIEW);
} else
{
if (model.getHeader().equals(dataList.get(position - ).getHeader())) //当前Item头部与上一个Item头部相同,则隐藏头部
{
holder.headerLayout.setVisibility(View.GONE);
holder.itemView.setTag(NONE_STICKY_VIEW);
} else
{
holder.headerLayout.setVisibility(View.VISIBLE);
holder.itemView.setTag(HAS_STICKY_VIEW);
}
}
}
...
RecyclerView滚动监听类代码:
/**
* 监听RecyclerView滚动,实现粘性头部
*/
private class RvScrollListener extends RecyclerView.OnScrollListener
{
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy)
{
super.onScrolled(recyclerView, dx, dy);
View stickyInfoView = recyclerView.getChildAt();//获取头部View
if (stickyInfoView != null && stickyInfoView.getContentDescription() != null)
{
headerView.setVisibility(View.VISIBLE);
headerViewText.setText(String.valueOf(stickyInfoView.getContentDescription()));
}
View transInfoView = recyclerView.findChildViewUnder(headerView.getMeasuredWidth() /
, headerView.getMeasuredHeight() + );//位于headerView下方的itemView(该坐标是否在itemView内)
if (transInfoView != null && transInfoView.getTag() != null)
{
int tag = (int) transInfoView.getTag();
int deltaY = transInfoView.getTop() - headerView.getMeasuredHeight();
if (tag == StickyHeaderAdapter.HAS_STICKY_VIEW)//当Item包含粘性头部一类时
{
if (transInfoView.getTop() > )//当Item还未移动出顶部时
{
headerView.setTranslationY(deltaY);
} else//当Item移出顶部,粘性头部复原
{
headerView.setTranslationY();
}
} else//当Item不包含粘性头部时
{
headerView.setTranslationY();
}
}
}
}
最后给RecyclerView添加滚动监听:
mRecyclerView.addOnScrollListener(new RvScrollListener());
绘制ItemDecoration实现方式
请参考 RecyclerView探索之通过ItemDecoration实现StickyHeader效果
源码地址:github