当前位置: 首页 > news >正文

material-scrolling源码精读:RecyclerViewHolder如何桥接ObservableRecyclerView滚动状态

material-scrolling源码精读:RecyclerViewHolder如何桥接ObservableRecyclerView滚动状态

【免费下载链接】material-scrollingAndroid library for material scrolling techniques.项目地址: https://gitcode.com/gh_mirrors/ma/material-scrolling

material-scrolling 是一款 Android Material 滚动技术方案库,把 Google 设计规范的滚动交互变成几行 API。本文带你逐段精读它的核心源码:RecyclerViewHolder究竟如何桥接ObservableRecyclerView的滚动状态,把一次触摸手势变成标题平移、背景视差、FAB 缩放的完整链路。

一句话总览:ObservableRecyclerView 感知手势 → RecyclerViewHolder 归一化坐标 → BehaviorDispatcher 广播 → Behavior 们各自动画

模块导航:先看地图再读代码 🗺️

模块文件角色
library/src/main/java/jp/satorufujiwara/scrolling/RecyclerViewHolder.java本文主角:滚动状态桥接器
library/src/main/java/jp/satorufujiwara/scrolling/MaterialScrollingLayout.java容器布局,负责"接线"
library/src/main/java/jp/satorufujiwara/scrolling/MaterialScrollingViewPager.javaViewPager 多页联动版本
library/src/main/java/jp/satorufujiwara/scrolling/BehaviorDispatcher.java事件广播中心
library/src/main/java/jp/satorufujiwara/scrolling/Behavior.java所有滚动行为的抽象基类
library/src/main/java/jp/satorufujiwara/scrolling/Utils.java递归查找 ObservableRecyclerView 的工具
sample/src/main/java/jp/satorufujiwara/scrolling/sample/MainActivity.java示例入口,看真实用法

想看完整演示?README 在arts/目录下附了三段 GIF(viewpager.gifimagefab.gifviewpager_land.gif),分别展示横向翻页、大图 FAB、横屏效果。

核心机制:滚动事件如何"过桥"

RecyclerView 本身只回调"我滚动了",不关心页面上其他 View 怎么动。material-scrolling 的答案是中间层桥接

触摸手势 │ ▼ ObservableRecyclerView ── 注册回调 ──▶ RecyclerViewHolder (桥) │ 归一化坐标 scrollY + 增量 dy │ 支持开关 / 缓存 / 同步滚动 ▼ BehaviorDispatcher (广播) │ ┌────────────────────────┼────────────────────┐ ▼ ▼ ▼ ScrollBehavior ParallaxBehavior FabBehavior (标题跟手平移) (背景视差偏移) (FAB 缩放消失)

逐段精读:RecyclerViewHolder 的 7 个关键设计

以下路径均相对仓库根目录,核心文件为 library/src/main/java/jp/satorufujiwara/scrolling/RecyclerViewHolder.java。

1️⃣ 构造即接线:两行代码完成桥接

this.recyclerView = recyclerView; this.recyclerView.setClipToPadding(false); recyclerView.setScrollViewCallbacks(new OnScrollDelegate(this));
  • 持有ObservableRecyclerView引用,并把回调"插线"到内部类OnScrollDelegate(第 72–94 行)——它只干一件事:把onScrollChangedonDownMotionEventonUpOrCancelMotionEvent三个事件原样转发给 holder 自己。
  • setClipToPadding(false):允许列表内容画进 padding 区,顶部大图的视觉空间由此而来。

2️⃣ flexibleHeight:让 RecyclerView "自带头部留白"

setFlexibleHeight()(第 28–31 行)把布局属性ms_flexible_height转成RecyclerView 顶部 padding

app:ms_flexible_height="240dp"

于是"标题区"不再是一个独立 View,而是列表自带的留白区域——这是整个方案的坐标系基准。

3️⃣ 坐标归一化:把"列表内部位置"换算成"页面滚动量"

getScrollY()(第 37–39 行)是桥的核心:

return isDirty ? scrollY : recyclerView.getCurrentScrollY() + flexibleHeight;
  • 实时位置 =getCurrentScrollY() + flexibleHeight,这样 scrollY 在"大图完全收起"时恰好等于 flexibleHeight,后续所有 Behavior 都用同一把尺子;
  • isDirty标志:当scrollTo()主动滚动后,回调还没来得及回来,就优先返回缓存值,保证 ViewPager 同步多页时坐标不穿帮(见第 4 节)。

4️⃣ 增量事件:一次滚动只发"差值"

void onScrolled(final int y) { isDirty = false; if (!isDispatchScroll) return; scrollY = y + flexibleHeight; behaviorDispatcher.onScrolled(scrollY, scrollY - preScrollY); preScrollY = scrollY; }

发给 Behavior 的是(scrollY, dy)两个参数——绝对位置 + 本次增量。dy让行为可以写"跟手回弹""惯性感知"这类依赖速度的效果。

5️⃣ 主动滚动:scrollTo 的反向桥

isDirty = true; scrollY = y; final LinearLayoutManager lm = (LinearLayoutManager) recyclerView.getLayoutManager(); lm.scrollToPositionWithOffset(0, -y);

桥是双向的:MaterialScrollingViewPager翻页时会用holder.scrollTo(...)非当前页同步到当前页位置(见 MaterialScrollingViewPager.java 的onPageScrollStateChanged),这就是多页"齐刷刷一起收起"的效果来源。

6️⃣ 事件开关:setIsDispatchScroll

MaterialScrollingLayoutaddView时创建 holder、removeView时关闭开关(MaterialScrollingLayout.java 第 50–67 行)。ViewPager 场景更讲究:onPageSelected时先关闭所有 holder 的开关,只打开当前页那个——彻底杜绝旧页残留回调污染动画。

7️⃣ 手势生命周期:按下 / 抬起同样被桥接

onDownMotionEventonUpOrCancelMotionEvent(ScrollState)也全部透传给BehaviorDispatcher。Behavior 拿到ScrollState(FLING / DRAG / IDLE)就能做"抬手后回弹"的决策,桥接的不仅是位置,还有手势语义

三个最容易踩坑的细节 ⚠️

  1. isDirty不是脏检查:它标记的是"我刚执行过主动scrollTo,回调值不可信",读源码时别按字面理解。
  2. 开关先于缓存setIsDispatchScroll(false)只拦事件,getScrollY()缓存值仍然有效,两者职责分离。
  3. 坐标系偏移:所有 Behavior 收到的 scrollY 都已+ flexibleHeight,写自定义行为时直接用getFlexibleHeight()做上限即可,例如内置的 ScrollBehavior.java:
ViewCompat.setTranslationY(target, -Math.min(scrollY, getFlexibleHeight()));

上手只需两步 🚀

第一步,布局里包一层容器并声明 flexible 区域(见 library/src/main/res/values/attrs.xml 定义的属性):

<jp.satorufujiwara.scrolling.MaterialScrollingLayout app:ms_flexible_height="240dp"> <com.github.ksoichiro.android.observablescrollview.ObservableRecyclerView android:layout_width="match_parent" android:layout_height="match_parent"/> </jp.satorufujiwara.scrolling.MaterialScrollingLayout>

第二步,代码里注册行为,一行一个效果:

materialScrollingLayout.addBehavior(bgImageView, new ParallaxBehavior()); materialScrollingLayout.addBehavior(titleTextView, new ScrollingBehavior());

内置行为都在 library/src/main/java/jp/satorufujiwara/scrolling/behavior/ 下,自定义只需继承 Behavior.java 重写onScrolled,范例参考 sample 的 FabBehavior 与 TitleBehavior。

依赖(jcenter):jp.satorufujiwara:material-scrolling:1.2.1+com.github.ksoichiro:android-observablescrollview:1.6.0

总结:这张"桥"值得抄的设计

  • 归一化:把"列表内部滚动"统一换算成"页面滚动量",一套坐标打天下;
  • 可插拔:回调、开关、缓存三个正交机制,让单页布局和多页 ViewPager 共用同一个 holder;
  • 广播式:一个 Dispatcher 一对多分发,Behavior 之间零耦合。

想动手验证,先 clone 仓库https://gitcode.com/gh_mirrors/ma/material-scrolling,跑 sample 工程,对照本文的 7 个设计点逐行读,你会发现不到 100 行的RecyclerViewHolder才是整套 Material 滚动魔法的引擎。

【免费下载链接】material-scrollingAndroid library for material scrolling techniques.项目地址: https://gitcode.com/gh_mirrors/ma/material-scrolling

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

http://www.cnnetsun.cn/news/4249363.html

相关文章:

  • axure-cn Axure 汉化语言包安装教程:15 分钟让 RP 9/10/11 变成中文界面
  • 如何为 doc2dash 编写自定义解析器:从 Parser 协议到 Patcher 的完整插件开发指南
  • WinScript 快速上手指南:把 Windows 精简、隐私与性能优化变成勾选操作
  • PDF补丁丁完全使用指南:免费开源PDF工具箱,书签编辑与批量处理快速上手
  • 灰色预测GM(1,1)模型:小样本时间序列预测的数学建模利器
  • 基于springboot的英语课程教学管理系统毕业设计项目源码
  • 【AI大模型】一文搞懂多模态大模型,从“文字专家“到“全能感知者“,零基础小白收藏这一篇就够了!!
  • 3步搭好企业微信审批超时提醒系统:EasyWeChat审批监控完整指南
  • GNOME 系统监视器 Applet:3 步快速在状态栏显示 CPU、内存与网速
  • 神奇弹幕 MagicalDanmaku 使用指南:一款免费的 B 站直播场控机器人如何接管你的直播间
  • 6 个下游聚合有 1 个 hang 住,Tomcat 200 个线程全卡死:CompletableFuture 编排的 4 个隐形约定
  • SillyTavern 性能优化:5 步快速提速清单,让角色卡和聊天变快变轻(附 config.yaml 参数速查)
  • 一条链接搞定B站视频下载与AI总结
  • 低剖面180W AC-DC电源设计:从效率到散热的全流程解析
  • MSLab 入门指南:用 3 条 PowerShell 命令搭出 Azure Local 测试集群
  • 为什么Venice值得关注:LinkedIn开源的行星级派生数据平台完整指南
  • KISS-Matcher是什么:MIT开源的3D点云配准利器,一文读懂FastRobust全局配准的完整原理
  • MT-GNN:连续时间网格演化与度量张量嵌入的脑形态预测
  • OBS 直播按键显示怎么做?Input Overlay 免费插件 5 分钟配置教程
  • 免费开源 Crimson 字体完整使用指南
  • AI奖励作弊第一课:ai-safety-gridworlds的tomato_watering浇番茄环境实战教程
  • 审查员常用链接
  • K8s集群Containerd运行时配置定时备份实操
  • 大模型VS大语言模型:核心区别详解,一篇文章带你搞清楚
  • llama-cpp-agent 生产部署与调优完全指南:采样参数、性能瓶颈与常见问题解决方案
  • Axure 汉化完整指南:4 步流程修复 Axure 11/10/9 英文界面
  • 基于STM32F4单片机的FreeRTOS移植思路及过程
  • copymanga-downloader 常见问题10问10答:杀毒软件误报、登录失败一次解决
  • WorkshopDL 创意工坊模组下载:5 分钟免费拿好你的第一个模组
  • 揭秘500+份模板从何而来:expo-react-native-cicd工作流生成器的代码实现原理