【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的诞生记》
相关推荐
zacksleo2 小时前
哪些鸿蒙原生应用在使用Flutter
前端·flutter·harmonyos
vvilkim3 小时前
Flutter布局系统全面解析:从基础组件到复杂界面构建
flutter
程序员老刘4 小时前
MCP:新时代的API,每个程序员都应该掌握
人工智能·flutter·mcp
恋猫de小郭4 小时前
Flutter 小技巧之:实现 iOS 26 的 “液态玻璃”
android·前端·flutter
帅次4 小时前
Flutter Container 组件详解
android·flutter·ios·小程序·kotlin·iphone·xcode
机器瓦力5 小时前
Flutter开发:扫码枪应用
flutter
帅次9 小时前
Flutter setState() 状态管理详细使用指南
android·flutter·ios·小程序·kotlin·android studio·iphone
Huang兄9 小时前
鸿蒙-flutter-使用FlutterEntry的路由管理和参数传递_中_flutter打开native页面传递参数
flutter·harmonyos·arkui
Huang兄9 小时前
鸿蒙-flutter-使用FlutterEntry的路由管理和参数传递_下_页面返回时透传数据
flutter·harmonyos·arkui
肥肥呀呀呀10 小时前
flutter bloc进行写app
flutter