Android RecyclerView吸顶效果:基于ItemDecoration的深度实现

490 阅读2分钟

一、吸顶效果的核心实现原理

RecyclerView 的吸顶效果,其核心思想是利用 ItemDecoration 的自定义绘制能力,在所有 Item 绘制完成后,动态地在 RecyclerView 顶部绘制一个悬浮的 Header。

1. 绘制流程的利用

  • RecyclerView 的绘制流程为:onDraw -> 绘制 ItemDecoration.onDraw() -> dispatchDraw(绘制所有子 View) -> 绘制 ItemDecoration.onDrawOver()
  • onDrawOver() :由于它在所有子 View 绘制完成后才执行,因此其内容可以覆盖在所有 Item 之上,天然适合用于绘制悬浮 Header。

2. 核心三步

  1. 查找:在 onDrawOver() 中,找到第一个可见的 Item,并判断它所属的组头是否应该吸顶。
  2. 测量与布局:获取 Header View,并对其进行测量和布局,以确定其尺寸。
  3. 绘制:根据滚动状态,计算 Header 的绘制位置,并将其绘制到 Canvas 上。

二、底层机制与源码分析

1. ItemDecoration的绘制机制

  • ItemDecorationonDrawOver() 方法提供了 Canvas,允许开发者直接在 RecyclerView 的画布上进行绘制。
  • onDrawOver() 中,开发者需要手动调用 headerView.draw(c) 方法,将 Header View 的内容绘制到 Canvas 上。

2. 布局与测量

  • LayoutManager 提供了获取 Item 位置和尺寸的 API,如 getDecoratedTop()
  • onDrawOver() 中,我们需要手动调用 View.measure()View.layout() 方法,对 Header View 进行测量和布局。但为了优化性能,我们应该缓存 Header 的尺寸,避免在每次绘制时都进行重复的测量。

3. 滚动监听

  • 通过 RecyclerView.OnScrollListener 监听滚动事件,当滚动发生时,调用 RecyclerView.invalidate() 触发 onDrawOver() 的重绘。

三、通用解决方案与优化

1. 外部接口与数据模型

  • 为了使 StickyHeaderDecoration 具备通用性,我们可以定义一个接口(如 StickyHeaderInterface),让 Adapter 来实现。这个接口提供了判断 Item 是否为 Header、获取 Header 数据等方法。

2. Header View的复用

  • 为了优化性能,我们应该复用 Header View,避免在每次绘制时都创建新对象。
  • 方案:创建一个 ViewHolder 缓存池,用于缓存 Header View。在 onDrawOver() 中,优先从缓存池中获取 ViewHolder,然后调用 onBindHeaderView() 绑定数据。

3. 事件处理

  • 点击穿透:由于 Header 是在 onDrawOver() 中绘制的,它实际上并没有一个真实的 View 实例。因此,它的点击事件不会被系统自动处理。
  • 解决方案:通过 RecyclerView.addOnItemTouchListener() 监听触摸事件。在 onInterceptTouchEvent() 中,判断触摸坐标是否在 Header 的绘制区域内。如果是,onInterceptTouchEvent() 返回 true,并手动处理 Header 的点击事件。