【Flutter技术分享】Scrollbar实现原理解析

0 Scrollbar简介

  • Scrollbar是常用的一种控件,几乎所有的UI平台都有这个控件,它可以指示当前在可滚动页面的位置、也可以通过它快速跳转到相应的位置;
  • 在移动平台,Flutter默认不显示Scrollbar,在Desktop平台,Flutter会为可滚动的控件自动添加scrollbar;
  • 将ScrollView包裹在Scrollbar内部,就可以为其添加显示Scrollbar;

Flutter官方关于Scrollbar控件的介绍、油管视频

dart 复制代码
Scrollbar(
  child: ListView.builder(
    primary: true,
    itemCount: 20,
    itemBuilder: (BuildContext context, int index) {
      return Column(
        children: [
          SizedBox( 
            width: MediaQuery.of(context).size.width,
            child: Center(
              child: Text(
                'Item    $index',
                style: const TextStyle(fontSize: 20),
              ),
            ),
          ),
          const Divider(
            color: Colors.black,
            endIndent: 20,
          )
        ],
      );
    },
  ),
)

1 Scrollbar建模与算法

建模:

  • 视窗区域的高度:viewportDimension
  • 可滚动控件内容的长度:totalContentExtent
  • 当前可滚动控件的滚动位移:offset

算法实现:

  • thumb的长度thumbExtent:(viewportDimension / totalContentExtent) * viewportDimension
  • 可滚动的长度scrollableExtent:totalContentExtent - viewportDimension
  • thumb的起始位置偏移:thumbOffset:(offset / scrollableExtent) * (viewportDimension - thumbExtent)

2 Flutter的实现

Flutter框架中,当ScrollView发生滚动时候,会向上发送ScrollNotification通知,通知中有ScrollMetrics属性,根据这个属性就可以绘制Scrollbar了,是不是很简单呢?

dart 复制代码
return FixedScrollMetrics(
      minScrollExtent: minScrollExtent ?? (hasContentDimensions ? this.minScrollExtent : null),
      maxScrollExtent: maxScrollExtent ?? (hasContentDimensions ? this.maxScrollExtent : null),
      pixels: pixels ?? (hasPixels ? this.pixels : null),
      viewportDimension: viewportDimension ?? (hasViewportDimension ? this.viewportDimension : null),
      axisDirection: axisDirection ?? this.axisDirection,
      devicePixelRatio: devicePixelRatio ?? this.devicePixelRatio,
);

代码解析

RawScrollbarState.build(BuildContext context)

  • ① 最内层child下面封装的是ScrollView
  • ② CustomPait通过canvas绘制Scrollbar
  • ③ MouseRegin响应Desktop平台上鼠标事件
  • ④ Scrollbar的手势处理,例如拖动、点击等
  • ⑤ 对鼠标滚轮、Trackpad等外设的响应
  • ⑥ NotificationListener是对可滚动组件的滚动信息的订阅,用以支持CustiomPait的绘制


RawScrollbarState._handleScrollMetricsNotification()

  • 收到ScrollView滚动信息后,调用scrollbarPainter.update()更新CustomPaint的painter信息

ScrollbarPainter.update()

  • ① scrollbarPainter存储最新的滚动信息
  • ② 通知RenderCustomPaint需要重新绘制

ScrollbarPainter.paint()

这里的算法就是我们前面讲到的算法实现:

  • ① 计算Scrollbar的thumb的尺寸
  • ② 计算thumb的起始位置偏移
  • ③ 通过canvas绘制Scrollbar
  • ① 先绘制Track区域,支持圆角、非圆角、Border;
  • ② 再绘制thumb区域,支持圆角、非圆角、和自定义形状;

3 总结

综上,Flutter的Scrollbar工作和渲染原理如下:

当前Flutter提供的Scrollbar控件还不支持前后的控制Button,如果开发者想使用此功能,还需要通过三方库或者自定义实现。了解了Scrollbar的工作原理,有助于开发者更好的使用Scrollbar控件,解决使用过程中出现的问题,也方便开发者开发自定义的Scrollbar组件。

作者长期活跃在Flutter开源社区,欢迎大家一起参与开源社区的共建,如果您也有意愿参与Flutter社区的贡献,可以与作者联系。-->GITHUB

您也许还对这些Flutter技术分享感兴趣:

  1. 《社区说|从Flutter Key 深入剖析UI架构设计原理》
  2. 《社区说|Flutter 长列表 Lazy Loading 机制解析》
  3. 《【Flutter技术分享】ScrollMetricsNotification的诞生记》
相关推荐
stringwu7 小时前
Flutter 开发必备:MVI 架构的高效实现指南
前端·flutter
程序员老刘1 天前
Flutter版本选择指南:3.44系列继续观望 | 2026年6月
flutter·ai编程·客户端
用户965597361903 天前
Provider vs Bloc vs GetX vs Riverpod:Flutter 状态管理方案怎么选?
flutter
恋猫de小郭3 天前
Flutter Patchwork,不用 Fork 改依赖包源码的第三方工具
android·前端·flutter
程序员老刘3 天前
跑分第一的编程大模型,我为啥不用?
flutter·ai编程·vibecoding
恋猫de小郭4 天前
苹果 AirPods 协议,Android 也可以使用完整版 AirPods 能力
android·前端·flutter
张风捷特烈4 天前
Flutter 类库大揭秘#01 | path_provider架构与设计
android·flutter
恋猫de小郭6 天前
Android 限制侧载新进展,谷歌联合国内厂商推验证计划
android·前端·flutter
恋猫de小郭6 天前
解读 Android 17 全新内存限制,有没有“豁免”后门?
android·前端·flutter
程序员老刘9 天前
跨平台开发地图 | 2026年6月
flutter·ai编程·客户端