【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的诞生记》
相关推荐
程序员老刘2 天前
跨平台开发地图 | 2026年10月
flutter·ai编程·客户端
林瞅瞅2 天前
Flutter 开发环境从零搭建与调试记录
flutter
FungLeo2 天前
成为全栈·Flutter App 篇·Markdown 编辑器:编辑、预览与离开保护
flutter·移动开发·markdown编辑器·表单设计·成为全栈·草稿保存
FungLeo2 天前
成为全栈·Flutter App 篇·会员中心:资料、密码、通知与私有数据缓存
flutter·dart·身份认证·数据隔离·成为全栈·会员中心
穆梓兰煊3 天前
Flutter端云协同推理架构解析
flutter·github
FungLeo3 天前
成为全栈·Flutter App 篇·内置 WebView:网页历史、App 返回与外链安全
flutter·网络安全·移动开发·webview·路由管理·成为全栈
m0_738185823 天前
Flutter 鸿蒙化实战:volume_controller 适配 OpenHarmony,系统音量控制
flutter·华为·harmonyos·鸿蒙
FungLeo3 天前
成为全栈·Flutter App 篇·Flutter Markdown 阅读器:支持范围与渲染边界
flutter·markdown·dart·代码高亮·成为全栈·移动阅读
m0_738185823 天前
Flutter 鸿蒙化实战:webview_cookie_manager 适配 OpenHarmony,WebView Cookie 管理
flutter·华为·harmonyos·鸿蒙