【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的诞生记》
相关推荐
jump_jump17 小时前
GetX — Flutter 的瑞士军刀,还是过度封装的陷阱?
flutter·设计模式·前端框架
MonkeyKing1 天前
三棵树彻底拆解(Widget / Element / RenderObject)
flutter·dart
Lanren的编程日记1 天前
Flutter 鸿蒙应用错误处理优化实战:完善全局异常捕获,全方位提升应用稳定性
flutter·华为·harmonyos
Lanren的编程日记1 天前
Flutter鸿蒙应用开发:网络请求优化实战,全方位提升请求稳定性与性能
网络·flutter·harmonyos
IntMainJhy1 天前
【futter for open harmony】Flutter 鸿蒙聊天应用实战:shared_preferences 本地键值存储适配指南[特殊字符]
flutter·华为·harmonyos
IntMainJhy1 天前
【Flutter for OpenHarmony 】第三方库鸿蒙电商实战|首页模块完整实现[特殊字符]
flutter·华为·harmonyos
梦想不只是梦与想1 天前
flutter 与原生通信的底层原理(二)
flutter
Lanren的编程日记1 天前
Flutter 鸿蒙应用离线模式实战:无网络也能流畅使用
网络·flutter·harmonyos
IntMainJhy1 天前
【Flutter for OpenHarmony 】第三方库 聊天应用:Provider 状态管理实战指南
flutter·华为·harmonyos