Saltar al contenido principal

El singleton window está deprecado

En preparación para admitir múltiples vistas y múltiples ventanas, el singleton window ha sido deprecado.

Resumen

#

En preparación para admitir múltiples vistas y múltiples ventanas, el singleton window ha sido deprecado. El código que dependía anteriormente del singleton window debe buscar la vista específica sobre la que desea operar a través de la API View.of o interactuar directamente con PlatformDispatcher.

Contexto

#

Originalmente, Flutter asumía que una aplicación solo consistiría en una única vista (la ventana o window) en la que se puede dibujar el contenido. En un mundo multivista, esta asunción ya no tiene sentido y las API que codifican esta asunción han sido deprecadas. En su lugar, las aplicaciones y bibliotecas que dependían de estas API deben elegir una vista específica en la que desean operar y migrar a las nuevas API compatibles con multivista, tal como se describe en esta guía de migración.

Descripción del cambio

#

Las API que se han deprecado como parte de este cambio son:

  • La propiedad global window expuesta por dart:ui.
  • The window property on the BaseBinding class, which is usually accessed via
    • GestureBinding.instance.window,
    • SchedulerBinding.instance.window,
    • ServicesBinding.instance.window,
    • PaintingBinding.instance.window,
    • SemanticsBinding.instance.window,
    • RendererBinding.instance.window,
    • WidgetsBinding.instance.window, o
    • WidgetTester.binding.window.
  • La clase SingletonFlutterView de dart:ui.
  • TestWindow de flutter_test, sus constructores, y todas sus propiedades y métodos.

Existen las siguientes opciones para migrar el código de la aplicación y de la biblioteca que depende de estas API deprecadas:

Si hay un BuildContext disponible, considera buscar el FlutterView actual a través de View.of. Esto devuelve el FlutterView en el que se dibujarán los widgets construidos por el método build asociado con el contexto dado. El FlutterView proporciona acceso a la misma funcionalidad que estaba disponible anteriormente en la clase deprecada SingletonFlutterView devuelta por las propiedades deprecadas de window mencionadas anteriormente. Sin embargo, algunas de las funcionalidades específicas de la plataforma se han trasladado a PlatformDispatcher, a la cual se puede acceder desde el FlutterView devuelto por View.of a través de FlutterView.platformDispatcher. El uso de View.of es la forma preferida de migrar fuera de las propiedades deprecadas mencionadas anteriormente.

Si no hay un BuildContext disponible para buscar un FlutterView, se puede consultar directamente PlatformDispatcher para acceder a la funcionalidad específica de la plataforma. También mantiene una lista de todos los FlutterViews disponibles en PlatformDispatcher.views para acceder a la funcionalidad específica de la vista. Si es posible, se debe acceder a PlatformDispatcher a través de un binding (por ejemplo, WidgetsBinding.instance.platformDispatcher) en lugar de utilizar la propiedad estática PlatformDispatcher.instance. Esto garantiza que la funcionalidad de PlatformDispatcher se pueda simular (mock) correctamente en las pruebas.

Pruebas

#

Para las pruebas que accedían a la propiedad WidgetTester.binding.window para cambiar las propiedades de la ventana para las pruebas, están disponibles las siguientes migraciones:

En las pruebas escritas con testWidgets, se han añadido dos nuevas propiedades que juntas reemplazan la funcionalidad de TestWindow.

  • WidgetTester.view will provide a TestFlutterView that can be modified similarly to WidgetTester.binding.window, but with only view-specific properties such as the size of a view, its display pixel ratio, etc.
    • WidgetTester.viewOf está disponible para ciertos casos de uso multivista, pero no debería ser necesario para ninguna migración desde WidgetTester.binding.window.
  • WidgetTester.platformDispatcher proporcionará acceso a un TestPlatformDispatcher que se puede utilizar para modificar propiedades específicas de la plataforma como la configuración regional (locale) de la plataforma, si ciertas características del sistema están disponibles, etc.

Guía de migración

#

En lugar de acceder a la propiedad estática window, el código de la aplicación y de la biblioteca que tiene acceso a un BuildContext debe usar View.of para buscar el FlutterView con el que está asociado el contexto. Algunas propiedades se han movido a PlatformDispatcher accesible desde la vista a través del getter platformDispatcher.

Código antes de la migración:

dart
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.');
}

Código después de la migración:

dart
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.');
}

Si no hay un BuildContext disponible, se puede consultar directamente el PlatformDispatcher expuesto por los bindings.

Código antes de la migración:

dart
double getTextScaleFactor() {
  return WidgetsBinding.instance.window.textScaleFactor;
}

Código después de la migración:

dart
double getTextScaleFactor() {
  // View.of(context).platformDispatcher.textScaleFactor if a BuildContext is available, otherwise:
  return WidgetsBinding.instance.platformDispatcher.textScaleFactor;
}

Pruebas

#

En las pruebas escritas con testWidget, se deben usar en su lugar los nuevos accesores view y platformDispatcher.

Configurar propiedades específicas de la vista

#

TestFlutterView también se ha esforzado por hacer que la API de pruebas sea más clara y más concisa al usar setters con el mismo nombre que su getter relacionado en lugar de setters con el sufijo TestValue.

Código antes de la migración:

dart
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;
});

Código después de la migración

dart
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;
});

Restablecer propiedades específicas de la vista

#

TestFlutterView conserva la capacidad de restablecer propiedades individuales o toda la vista pero, para ser más claros y consistentes, el nombre de estos métodos ha cambiado de clear<property>TestValue y clearAllTestValues a reset<property> y reset respectivamente.

Restablecer propiedades individuales
#

Código antes de la migración:

dart
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);
});

Código después de la migración

dart
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);
});
Restablecer todas las propiedades a la vez
#

Código antes de la migración:

dart
testWidget('test name', (WidgetTester tester) async {
  addTearDown(tester.binding.window.clearAllTestValues);
});

Código después de la migración

dart
testWidget('test name', (WidgetTester tester) async {
  addTearDown(tester.view.reset);
});

Configurar propiedades específicas de la plataforma

#

TestPlatformDispatcher conserva la misma funcionalidad y esquema de nombres para los setters de prueba que tenía TestWindow, por lo que la migración de propiedades específicas de la plataforma consiste principalmente en llamar a los mismos setters en el nuevo accesor WidgetTester.platformDispatcher.

Código antes de la migración:

dart
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;
});

Código después de la migración:

dart
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;
});

Restablecer propiedades específicas de la plataforma

#

De manera similar a la configuración de propiedades, el restablecimiento de propiedades específicas de la plataforma consiste principalmente en cambiar del accesor binding.window al accesor platformDispatcher.

Restablecer propiedades individuales
#

Código antes de la migración:

dart
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);
});

Código después de la migración:

dart
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);
});
Restablecer todas las propiedades a la vez
#

Código antes de la migración:

dart
testWidgets('test name', (WidgetTester tester) async {
  addTeardown(tester.binding.window.clearAllTestValues);
});

Código después de la migración:

dart
testWidgets('test name', (WidgetTester tester) async {
  addTeardown(tester.platformDispatcher.clearAllTestValues);
});

Timeline

#

Introducido en la versión: 3.9.0-13.0.pre.20
En la versión estable: 3.10.0

Referencias

#

Documentación de la API:

Issues relevantes:

PRs relevantes: