设计RecycleView中的点击以及顶部悬浮(吸顶)
一、设计目标以及实现内容展示
设计目标
- “通讯录”页面中能显示分组以及联系人
- “通讯录”页面可以滑动且分组顶部悬浮
- “通讯录”页面中的联系人点击后会显示当前联系人
- “通讯录”页面布局清晰,运行流畅
实现内容展示
水印没去掉。。希望大佬们海涵
二,详细思路以及实现
布局文件
- 在“通讯录”页面中有一个RelativeLayout以及一个RecycleView,并且使用include引用顶部的分组框
- 联系人(item)中有一个LineaLayout包含一个TextView并使用include引用顶部的分组框
- 分组框中有一个TextView
“通讯录”页面代码:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/tab03_1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:overScrollMode="never"
android:scrollbars="none" />
<include layout="@layout/tab03_include_recycle_item" />
</RelativeLayout>
联系人页面代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<include layout="@layout/tab03_include_recycle_item" />
<TextView
android:id="@+id/tab03_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="14dp"
android:text="@string/app_name" />
</LinearLayout>
分组框页面代码
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/tab03_header_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorAccent"
android:padding="10dp"
android:text="通讯录"
android:textColor="@android:color/white"
android:textSize="20sp">
</TextView>
RecycleView设计
- ContactData的设计
- ContactAdapter的设计
- ContactFragment的设计 (具体代码附在文章结尾,此处只说明思路和展示关键代码)
运行流程: 当我们滚动RecycleView时,滚动监听会根据item的顶部悬浮框是否是第一个头部以及有无头部来设置其内容,点击item时,点击监听会显示当前内容
ContactData的设计
ContactData中包含分组名:group;联系人姓名:name ,以及它们的get,set方法
ContactAdapter的设计
- 构造函数:传入一个Context
- setContactDataList():设置一个ContactData的列表并赋值,动态更新
- onCreateViewHolder():设置View并返回ContactViewHolder
- onBindViewHolder():设置顶部悬浮通过是否是第一个头部,以及有无头部来判断;设置点击事件
- getItemCount():根据列表是否为空返回列表的长度
onBindViewHolder() 代码示例:
public static final int FIRST_STICKY_VIEW = 1;
public static final int HAS_STICKY_VIEW = 2;
public static final int NONE_STICKY_VIEW = 3;
public void onBindViewHolder(@NonNull ContactViewHolder holder, int position) {
final String content = mList.get(position).getName();
ContactData stickyData = mList.get(position);
holder.tvName.setText(stickyData.getName());
if (position == 0) {
holder.tvGroup.setVisibility(View.VISIBLE);
holder.tvGroup.setText(stickyData.group);
holder.itemView.setTag(FIRST_STICKY_VIEW);
} else {
if (!TextUtils.equals(stickyData.group, mList.get(position - 1).group)) {
holder.tvGroup.setVisibility(View.VISIBLE);
holder.tvGroup.setText(stickyData.group);
holder.itemView.setTag(HAS_STICKY_VIEW);
} else {
holder.tvGroup.setVisibility(View.GONE);
holder.itemView.setTag(NONE_STICKY_VIEW);
}
}
holder.itemView.setContentDescription(stickyData.group);
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(mContext, "你点击的是:" + content, Toast.LENGTH_SHORT).show();
}
});
}
ContactFragment的设计
- 使用inflater.inflate将View实例化
- initView():初始化RecycleView,设置adapter,并进行滚动监听
- initList():初始化List,将数据添加到List中
- initData() :初始化mDataList,将mList中的数据切割并加入到mDataList
initView()代码示例:
private void initView() {
RecyclerView recyclerView = view.findViewById(R.id.tab03_1);
adapter = new ContactAdapter(getActivity());
final TextView tvGroup = view.findViewById(R.id.tab03_header_view);
LinearLayoutManager manager = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(manager);
recyclerView.setHasFixedSize(true);
recyclerView.setAdapter(adapter);
adapter.setContactDataList(mDataList);
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
View stickyInfoView = recyclerView.findChildViewUnder(
tvGroup.getMeasuredWidth() / 2, 5);
if (stickyInfoView != null && stickyInfoView.getContentDescription() != null) {
tvGroup.setText(String.valueOf(stickyInfoView.getContentDescription()));
}
View transInfoView = recyclerView.findChildViewUnder(
tvGroup.getMeasuredWidth() / 2, tvGroup.getMeasuredHeight() + 1);
if (transInfoView != null && transInfoView.getTag() != null) {
int transViewStatus = (int) transInfoView.getTag();
int dealtY = transInfoView.getTop() - tvGroup.getMeasuredHeight();
if (transViewStatus == ContactAdapter.HAS_STICKY_VIEW) {
if (transInfoView.getTop() > 0) {
tvGroup.setTranslationY(dealtY);
} else {
tvGroup.setTranslationY(0);
}
} else if (transViewStatus == ContactAdapter.NONE_STICKY_VIEW) {
tvGroup.setTranslationY(0);
}
}
}
});
}
三,总结
本项目的难点在于滚动监听的设置,及如何根据item的顶部悬浮框是否为第一个头部以及有无头部来设置其内容。应该先通过滚动监听来监听此时position的变化,然后同过position的变化来设置item的顶部悬浮框是否为第一个头部以及有无头部,然后在通过这一点来设置RecycleView中的内容。
不足之处,希望各路大佬指正。