【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的诞生记》
相关推荐
早起的年轻人5 小时前
Flutter String 按 ,。分割
flutter
helloxmg14 小时前
鸿蒙harmonyos next flutter通信之MethodChannel获取设备信息
flutter
helloxmg15 小时前
鸿蒙harmonyos next flutter混合开发之开发package
flutter·华为·harmonyos
lqj_本人2 天前
flutter_鸿蒙next_Dart基础②List
flutter
lqj_本人2 天前
flutter_鸿蒙next_Dart基础①字符串
flutter
The_tuber_sadness2 天前
【Flutter】- 基础语法
flutter
helloxmg2 天前
鸿蒙harmonyos next flutter通信之BasicMessageChannel获取app版本号
flutter
linpengteng2 天前
使用 Flutter 开发数字钱包应用(Dompet App)
前端·flutter·firebase