Android Studio 学习(二)

312 阅读2分钟

设计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中的内容。

不足之处,希望各路大佬指正。

gitee源码