窗口单例已弃用
摘要
#为了准备支持多个视图和多个窗口,window
单例已被弃用。以前依赖于 window
单例的代码需要通过 View.of
API 查找其想要操作的特定视图,或直接与 PlatformDispatcher
交互。
上下文
#最初,Flutter 假设应用程序仅包含一个视图(window
),内容可以绘制到其中。在多视图世界中,此假设不再有意义,并且对该假设进行编码的 API 已被弃用。相反,依赖于这些 API 的应用程序和库必须选择它们想要操作的特定视图,并迁移到新的多视图兼容 API,如本迁移指南中所述。
更改说明
#作为此更改的一部分而被弃用的 API 为
dart:ui
公开的全局window
属性。BaseBinding
类上的window
属性,通常通过以下方式访问GestureBinding.instance.window
,SchedulerBinding.instance.window
,ServicesBinding.instance.window
,PaintingBinding.instance.window
,SemanticsBinding.instance.window
,RendererBinding.instance.window
,WidgetsBinding.instance.window
或WidgetTester.binding.window
.
- 来自
dart:ui
的SingletonFlutterView
类。 - 来自
flutter_test
的TestWindow
、其构造函数以及所有属性和方法。
以下选项可用于迁移依赖于这些已弃用 API 的应用程序和库代码
如果 BuildContext
可用,请考虑通过 View.of
查找当前的 FlutterView
。这将返回 FlutterView
,其中将绘制与给定上下文关联的 build
方法构建的小部件。FlutterView
提供对先前在上述已弃用的 window
属性返回的已弃用的 SingletonFlutterView
类上可用的相同功能的访问。但是,一些特定于平台的功能已移至 PlatformDispatcher
,可以通过上述 View.of
返回的 FlutterView
通过 FlutterView.platformDispatcher
访问。使用 View.of
是从上述已弃用属性迁移的首选方法。
如果 BuildContext
不可用以查找 FlutterView
,则可以直接查询 PlatformDispatcher
以访问特定于平台的功能。它还在 PlatformDispatcher.views
中维护所有可用 FlutterView
的列表,以访问特定于视图的功能。如果可能,应通过绑定(例如 WidgetsBinding.instance.platformDispatcher
)访问 PlatformDispatcher
,而不是使用静态 PlatformDispatcher.instance
属性。这确保了 PlatformDispatcher
的功能可以在测试中被正确模拟。
测试
#对于访问 WidgetTester.binding.window
属性以更改窗口属性以进行测试的测试,可以使用以下迁移
在使用 testWidgets
编写的测试中,已添加了两个新属性,它们共同替换了 TestWindow
的功能。
WidgetTester.view
将提供一个TestFlutterView
,可以对其进行修改,类似于WidgetTester.binding.window
,但仅限于特定于视图的属性,例如视图的大小、其显示像素比率等。WidgetTester.viewOf
可用于某些多视图用例,但对于从WidgetTester.binding.window
迁移的任何操作都不应需要。
WidgetTester.platformDispatcher
将提供对TestPlatformDispatcher
的访问,该访问器可用于修改特定于平台的属性,例如平台的语言环境、某些系统功能是否可用等。
迁移指南
#不要访问静态 window
属性,而是应该访问 BuildContext
的应用程序和库代码应该使用 View.of
来查找上下文关联的 FlutterView
。一些属性已移至可通过 platformDispatcher
getter 从视图访问的 PlatformDispatcher
。
迁移前的代码
Widget build(BuildContext context) {
final double dpr = WidgetsBinding.instance.window.devicePixelRatio;
final Locale locale = WidgetsBinding.instance.window.locale;
return Text('The device pixel ratio is $dpr and the locale is $locale.');
}
迁移后的代码
Widget build(BuildContext context) {
final double dpr = View.of(context).devicePixelRatio;
final Locale locale = View.of(context).platformDispatcher.locale;
return Text('The device pixel ratio is $dpr and the locale is $locale.');
}
如果 BuildContext
不可用,则可以直接查询绑定公开的 PlatformDispatcher
。
迁移前的代码
double getTextScaleFactor() {
return WidgetsBinding.instance.window.textScaleFactor;
}
迁移后的代码
double getTextScaleFactor() {
// View.of(context).platformDispatcher.textScaleFactor if a BuildContext is available, otherwise:
return WidgetsBinding.instance.platformDispatcher.textScaleFactor;
}
测试
#在使用 testWidget
编写的测试中,应使用新的 view
和 platformDispatcher
访问器代替。
设置特定于视图的属性
#TestFlutterView
还努力通过使用与相关 getter 同名的 setter(而不是使用 TestValue
后缀的 setter)来使测试 API 更清晰、更简洁。
迁移前的代码
testWidget('test name', (WidgetTester tester) async {
tester.binding.window.devicePixelRatioTestValue = 2.0;
tester.binding.window.displayFeaturesTestValue = <DisplayFeatures>[];
tester.binding.window.gestureSettingsTestValue = const GestureSettings(physicalTouchSlop: 100);
tester.binding.window.paddingTestValue = FakeViewPadding.zero;
tester.binding.window.physicalGeometryTestValue = const Rect.fromLTRB(0,0, 500, 800);
tester.binding.window.physicalSizeTestValue = const Size(300, 400);
tester.binding.window.systemGestureInsetsTestValue = FakeViewPadding.zero;
tester.binding.window.viewInsetsTestValue = FakeViewPadding.zero;
tester.binding.window.viewPaddingTestValue = FakeViewPadding.zero;
});
迁移后的代码
testWidget('test name', (WidgetTester tester) async {
tester.view.devicePixelRatio = 2.0;
tester.view.displayFeatures = <DisplayFeatures>[];
tester.view.gestureSettings = const GestureSettings(physicalTouchSlop: 100);
tester.view.padding = FakeViewPadding.zero;
tester.view.physicalGeometry = const Rect.fromLTRB(0,0, 500, 800);
tester.view.physicalSize = const Size(300, 400);
tester.view.systemGestureInsets = FakeViewPadding.zero;
tester.view.viewInsets = FakeViewPadding.zero;
tester.view.viewPadding = FakeViewPadding.zero;
});
重置特定于视图的属性
#TestFlutterView
保留了重置单个属性或整个视图的功能,但是,为了更清晰和一致,这些方法的命名已从 clear<property>TestValue
和 clearAllTestValues
分别更改为 reset<property>
和 reset
。
重置单个属性
#迁移前的代码
testWidget('test name', (WidgetTester tester) async {
addTearDown(tester.binding.window.clearDevicePixelRatioTestValue);
addTearDown(tester.binding.window.clearDisplayFeaturesTestValue);
addTearDown(tester.binding.window.clearGestureSettingsTestValue);
addTearDown(tester.binding.window.clearPaddingTestValue);
addTearDown(tester.binding.window.clearPhysicalGeometryTestValue);
addTearDown(tester.binding.window.clearPhysicalSizeTestValue);
addTearDown(tester.binding.window.clearSystemGestureInsetsTestValue);
addTearDown(tester.binding.window.clearViewInsetsTestValue);
addTearDown(tester.binding.window.clearViewPaddingTestValue);
});
迁移后的代码
testWidget('test name', (WidgetTester tester) async {
addTearDown(tester.view.resetDevicePixelRatio);
addTearDown(tester.view.resetDisplayFeatures);
addTearDown(tester.view.resetGestureSettings);
addTearDown(tester.view.resetPadding);
addTearDown(tester.view.resetPhysicalGeometry);
addTearDown(tester.view.resetPhysicalSize);
addTearDown(tester.view.resetSystemGestureInsets);
addTearDown(tester.view.resetViewInsets);
addTearDown(tester.view.resetViewPadding);
});
一次重置所有属性
#迁移前的代码
testWidget('test name', (WidgetTester tester) async {
addTearDown(tester.binding.window.clearAllTestValues);
});
迁移后的代码
testWidget('test name', (WidgetTester tester) async {
addTearDown(tester.view.reset);
});
设置特定于平台的属性
#TestPlatformDispatcher
保留了与 TestWindow
相同的功能和命名方案,因此特定于平台的属性的迁移主要包括在新的 WidgetTester.platformDispatcher
访问器上调用相同的 setter。
迁移前的代码
testWidgets('test name', (WidgetTester tester) async {
tester.binding.window.accessibilityFeaturesTestValue = FakeAccessibilityFeatures.allOn;
tester.binding.window.alwaysUse24HourFormatTestValue = false;
tester.binding.window.brieflyShowPasswordTestValue = true;
tester.binding.window.defaultRouteNameTestValue = '/test';
tester.binding.window.initialLifecycleStateTestValue = 'painting';
tester.binding.window.localesTestValue = <Locale>[const Locale('en-us'), const Locale('ar-jo')];
tester.binding.window.localeTestValue = const Locale('ar-jo');
tester.binding.window.nativeSpellCheckServiceDefinedTestValue = false;
tester.binding.window.platformBrightnessTestValue = Brightness.dark;
tester.binding.window.semanticsEnabledTestValue = true;
tester.binding.window.textScaleFactorTestValue = 2.0;
});
迁移后的代码
testWidgets('test name', (WidgetTester tester) async {
tester.platformDispatcher.accessibilityFeaturesTestValue = FakeAccessibilityFeatures.allOn;
tester.platformDispatcher.alwaysUse24HourFormatTestValue = false;
tester.platformDispatcher.brieflyShowPasswordTestValue = true;
tester.platformDispatcher.defaultRouteNameTestValue = '/test';
tester.platformDispatcher.initialLifecycleStateTestValue = 'painting';
tester.platformDispatcher.localesTestValue = <Locale>[const Locale('en-us'), const Locale('ar-jo')];
tester.platformDispatcher.localeTestValue = const Locale('ar-jo');
tester.platformDispatcher.nativeSpellCheckServiceDefinedTestValue = false;
tester.platformDispatcher.platformBrightnessTestValue = Brightness.dark;
tester.platformDispatcher.semanticsEnabledTestValue = true;
tester.platformDispatcher.textScaleFactorTestValue = 2.0;
});
重置特定于平台的属性
#与设置属性类似,重置特定于平台的属性主要包括从 binding.window
访问器更改为 platformDispatcher
访问器。
重置单个属性
#迁移前的代码
testWidgets('test name', (WidgetTester tester) async {
addTeardown(tester.binding.window.clearAccessibilityFeaturesTestValue);
addTeardown(tester.binding.window.clearAlwaysUse24HourFormatTestValue);
addTeardown(tester.binding.window.clearBrieflyShowPasswordTestValue);
addTeardown(tester.binding.window.clearDefaultRouteNameTestValue);
addTeardown(tester.binding.window.clearInitialLifecycleStateTestValue);
addTeardown(tester.binding.window.clearLocalesTestValue);
addTeardown(tester.binding.window.clearLocaleTestValue);
addTeardown(tester.binding.window.clearNativeSpellCheckServiceDefinedTestValue);
addTeardown(tester.binding.window.clearPlatformBrightnessTestValue);
addTeardown(tester.binding.window.clearSemanticsEnabledTestValue);
addTeardown(tester.binding.window.clearTextScaleFactorTestValue);
});
迁移后的代码
testWidgets('test name', (WidgetTester tester) async {
addTeardown(tester.platformDispatcher.clearAccessibilityFeaturesTestValue);
addTeardown(tester.platformDispatcher.clearAlwaysUse24HourFormatTestValue);
addTeardown(tester.platformDispatcher.clearBrieflyShowPasswordTestValue);
addTeardown(tester.platformDispatcher.clearDefaultRouteNameTestValue);
addTeardown(tester.platformDispatcher.clearInitialLifecycleStateTestValue);
addTeardown(tester.platformDispatcher.clearLocalesTestValue);
addTeardown(tester.platformDispatcher.clearLocaleTestValue);
addTeardown(tester.platformDispatcher.clearNativeSpellCheckServiceDefinedTestValue);
addTeardown(tester.platformDispatcher.clearPlatformBrightnessTestValue);
addTeardown(tester.platformDispatcher.clearSemanticsEnabledTestValue);
addTeardown(tester.platformDispatcher.clearTextScaleFactorTestValue);
});
一次重置所有属性
#迁移前的代码
testWidgets('test name', (WidgetTester tester) async {
addTeardown(tester.binding.window.clearAllTestValues);
});
迁移后的代码
testWidgets('test name', (WidgetTester tester) async {
addTeardown(tester.platformDispatcher.clearAllTestValues);
});
时间线
#包含在版本中:3.9.0-13.0.pre.20
稳定版发布:3.10.0
参考
#API 文档
View.of
FlutterView
PlatformDispatcher
TestPlatformDispatcher
TestFlutterView
TestWidgetsFlutterBinding.window
相关问题
相关 PR
除非另有说明,否则本网站上的文档反映了 Flutter 的最新稳定版本。页面上次更新时间:2024-04-04。 查看源代码 或 报告问题.