概述

#

ScrollBehavior现在可以自动将Scrollbar应用于桌面平台(Mac、Windows和Linux)上的可滚动组件。

背景

#

在此更改之前,Scrollbar是由开发者在所有平台上手动应用于可滚动组件的。这与在桌面平台上运行Flutter应用时的开发者预期不符。

现在,继承的ScrollBehavior会自动将Scrollbar应用于大多数可滚动组件。这类似于ScrollBehavior创建GlowingOverscrollIndicator的方式。少数不受此行为影响的组件列举如下。

为了更好地管理和控制此功能,ScrollBehavior也已更新。之前用于应用GlowingOverscrollIndicatorbuildViewportChrome方法已被弃用。取而代之的是,ScrollBehavior现在支持用于装饰视口的独立方法:buildScrollbarbuildOverscrollIndicator。这些方法可以被重写,以控制可滚动区域周围的构建内容。

此外,ScrollBehavior的子类MaterialScrollBehaviorCupertinoScrollBehavior已公开,允许开发者在框架中其他现有ScrollBehavior的基础上进行扩展和构建。这些子类以前是私有的。

变更说明

#

以前的方法要求开发者在所有平台上创建自己的Scrollbar。在某些用例中,需要将ScrollController提供给Scrollbar和可滚动组件。

dart
final ScrollController controller = ScrollController();
Scrollbar(
  controller: controller,
  child: ListView.builder(
    controller: controller,
    itemBuilder: (BuildContext context, int index) {
      return Text('Item $index');
    }
  )
);

现在,当在桌面执行时,ScrollBehavior会自动应用Scrollbar,并为你处理向Scrollbar提供ScrollController

dart
final ScrollController controller = ScrollController();
ListView.builder(
  controller: controller,
  itemBuilder: (BuildContext context, int index) {
   return Text('Item $index');
 }
);

框架中的一些组件不受此自动Scrollbar应用的影响。它们是:

  • EditableText,当maxLines为1时。
  • ListWheelScrollView
  • PageView
  • NestedScrollView

由于这些组件手动重写了继承的ScrollBehavior以移除Scrollbar,因此所有这些组件现在都带有一个scrollBehavior参数,以便可以提供一个替代重写。

此更改在开发过程中未导致任何测试失败、崩溃或错误消息,但如果您在桌面平台上手动添加Scrollbar,则可能导致您的应用程序中渲染出两个Scrollbar

如果您在应用程序中遇到这种情况,有几种方法可以控制和配置此功能。

  • 在桌面运行时,移除应用程序中手动应用的Scrollbar

  • 扩展ScrollBehaviorMaterialScrollBehaviorCupertinoScrollBehavior以修改默认行为。

    • 有了您自己的 ScrollBehavior,您可以通过设置 MaterialApp.scrollBehaviorCupertinoApp.scrollBehavior 将其应用于整个应用程序。
    • 或者,如果您只想将其应用于特定组件,请在相关组件上方添加一个 ScrollConfiguration,并使用您的自定义 ScrollBehavior

您的可滚动组件将继承并反映此行为。

  • 除了创建您自己的ScrollBehavior之外,改变默认行为的另一个选项是复制现有的ScrollBehavior,并切换所需的功能。
    • 在您的组件树中创建一个 ScrollConfiguration,并使用 copyWith 提供当前上下文中现有 ScrollBehavior 的修改副本。

迁移指南

#

移除桌面手动滚动条

#

迁移前的代码

dart
final ScrollController controller = ScrollController();
Scrollbar(
  controller: controller,
  child: ListView.builder(
    controller: controller,
    itemBuilder: (BuildContext context, int index) {
      return Text('Item $index');
    }
  )
);

迁移后的代码

dart
final ScrollController controller = ScrollController();
final Widget child = ListView.builder(
  controller: controller,
  itemBuilder: (BuildContext context, int index) {
    return Text('Item $index');
  }
);
// Only manually add a `Scrollbar` when not on desktop platforms.
// Or, see other migrations for changing `ScrollBehavior`.
switch (currentPlatform) {
  case TargetPlatform.linux:
  case TargetPlatform.macOS:
  case TargetPlatform.windows:
    return child;
  case TargetPlatform.android:
  case TargetPlatform.fuchsia:
  case TargetPlatform.iOS:
    return Scrollbar(
      controller: controller,
      child: child;
    );
}

为应用程序设置自定义 ScrollBehavior

#

迁移前的代码

dart
// MaterialApps previously had a private ScrollBehavior.
MaterialApp(
  // ...
);

迁移后的代码

dart
// MaterialApps previously had a private ScrollBehavior.
// This is available to extend now.
class MyCustomScrollBehavior extends MaterialScrollBehavior {
  // Override behavior methods like buildOverscrollIndicator and buildScrollbar
}

// ScrollBehavior can now be configured for an entire application.
MaterialApp(
  scrollBehavior: MyCustomScrollBehavior(),
  // ...
);

为特定组件设置自定义 ScrollBehavior

#

迁移前的代码

dart
final ScrollController controller = ScrollController();
ListView.builder(
  controller: controller,
  itemBuilder: (BuildContext context, int index) {
   return Text('Item $index');
 }
);

迁移后的代码

dart
// MaterialApps previously had a private ScrollBehavior.
// This is available to extend now.
class MyCustomScrollBehavior extends MaterialScrollBehavior {
  // Override behavior methods like buildOverscrollIndicator and buildScrollbar
}

// ScrollBehavior can be set for a specific widget.
final ScrollController controller = ScrollController();
ScrollConfiguration(
  behavior: MyCustomScrollBehavior(),
  child: ListView.builder(
    controller: controller,
    itemBuilder: (BuildContext context, int index) {
     return Text('Item $index');
    }
  ),
);

复制并修改现有 ScrollBehavior

#

迁移前的代码

dart
final ScrollController controller = ScrollController();
ListView.builder(
  controller: controller,
  itemBuilder: (BuildContext context, int index) {
   return Text('Item $index');
 }
);

迁移后的代码

dart
// ScrollBehavior can be copied and adjusted.
final ScrollController controller = ScrollController();
ScrollConfiguration(
  behavior: ScrollConfiguration.of(context).copyWith(scrollbars: false),
  child: ListView.builder(
    controller: controller,
    itemBuilder: (BuildContext context, int index) {
     return Text('Item $index');
    }
  ),
);

时间线

#

落地版本:2.2.0-10.0.pre
稳定版本:2.2.0

参考资料

#

API 文档

相关问题

相关 PR