После выпуска Flutter 3.10 вы могли заметить, что в его заметках о выпуске упоминается отказ от использования единого экземпляра окна (Window singleton
) и то, что это изменение направлено на поддержку будущей реализации многоконтурной системы.
Это улучшение предназначено для поддержки многоконтурной системы, которая более распространена в сценариях работы с ПК, но при этом должна совместима со смартфонами.
Как показано на следующем рисунке, если рассматривать конкретные сценарии API, основное внимание уделяется адаптации методов WidgetsBinding.instance.window
и MediaQueryData.fromWindow
, поскольку WidgetsBinding.instance.window
будет прекращён поддерживаться.
Вы можете не адаптироваться, но ваш код всё равно будет работать, хотя технический долг будет накапливаться.
Первый вопрос, который может возникнуть, заключается в том, почему вообще требуются сценарии использования WidgetsBinding.instance.window
. Вкратце можно сказать:
BuildContext
)MediaQueryData
, которые зависят от текущего контекста сборки, например изменения отображаемых данных из-за появления клавиатуры или влияние параметров Scaffold
> Подробнее об этом можно прочитать здесь: "MediaQuery и оптимизация сборки: секреты, которых вы не знали".С версии 3.10 для замены WidgetsBinding.instance.window
предлагается использовать новые API:
BuildContext
, можно использовать View.of
для получения объекта FlutterView
, что является рекомендованным способом.BuildContext
, можно использовать объект views
из PlatformDispatcher
.Заметьте, что теперь используется View.of
, а полученный объект называется FlutterView
, вместо «Window». Соответственно, метод MediaQueryData.fromWindow
также был прекращен поддерживаться и заменен на MediaQueryData.fromView
.
Это изменение основано на том факте, что изначально Flutter предполагал поддержку одного окна, поэтому существовал объект SingletonFlutterWindow
, предоставляющий множество функций, не связанных напрямую с окном, что делает его использование в многоконтурной системе необычным. Давайте подробнее рассмотрим особенности этих двух сценариев.
Перейдём к первому случаю — когда существует BuildContext. Ниже приведён пример кода, который показывает изменения в этом случае:
/// До версии 3.10
double dpr = WidgetsBinding.instance.window.devicePixelRatio;
Locale locale = WidgetsBinding.instance.window.locale;
double width =
MediaQueryData.fromWindow(WidgetsBinding.instance.window).size.width;
/// После версии 3.10
double dpr = View.of(context).devicePixelRatio;
Locale locale = View.of(context).platformDispatcher.locale;
double width =
MediaQueryData.fromView(View.of(context)).size.width;
```Как видно из этого кода, внутри `View` обязательно присутствует `InheritedWidget`, который передаётся через `BuildContext`. Это позволяет предоставлять параметры, аналогичные тем, что были доступны через `window`.
Параметры, полученные через `View.of`, имеют следующие характеристики:
- Когда свойства самого `FlutterView` изменяются, это не вызывает обновление связанного `context`. Это поведение аналогично тому, как работало `WidgetsBinding.instance.window`.
- Обновление происходит только тогда, когда сам `FlutterView` изменяется, например, когда `context` отрисовывается на другом `FlutterView`.
Таким образом, поведение `View.of` ориентировано на сценарий обновления при наличии нескольких `FlutterView`. Если требуется обновление, связанное с конкретными параметрами, такими как размер (`size`), следует использовать старый метод `MediaQuery.of` или `MediaQuery.maybeOf`.
Для каждого `FlutterView` важно, чтобы он был уникален и независим. В дереве виджетов один `FlutterView` может быть связан только с одним `View`. Это особенно важно для реализации `GlobalObjectKey`.

Краткий вывод: в случае существования `BuildContext` можно заменить `WidgetsBinding.instance.window` на `View.of(context)`, не беспокоясь о необходимости повторной конфигурации контекста, поскольку `View.of` работает только при смене `FlutterView`.## Отсутствие BuildContext
Для случаев, когда невозможно или不方便使用 `BuildContext`, официальная документация предлагает использовать API `PlatformDispatcher.views`. Однако, поскольку `get views` соответствует значению (`values`) карты (`Map`), это является объектом типа `Iterable`.
---
Перевод:
## Отсутствие BuildContext
Для случаев, когда невозможно или不方便使用 `BuildContext`, официальная документация предлагает использовать API `PlatformDispatcher.views`. Однако, поскольку `get views` соответствует значению (`values`) карты (`Map`), это является объектом типа `Iterable`.
---
Корректный перевод:
## Отсутствие BuildContext
Для случаев, когда невозможно или невозможно использование `BuildContext`, официальная документация предлагает использовать API `PlatformDispatcher.views`. Однако, поскольку `get views` соответствует значению (`values`) карты (`Map`), это является объектом типа `Iterable`.Тогда как нам следует использовать `PlatformDispatcher.views` в версии Dart 3.10 для адаптации ситуации, где отсутствует `BuildContext` для `WidgetsBinding.instance.window`?
Чтобы получить доступ к окну приложения без использования `BuildContext`, вы можете воспользоваться следующим подходом:
```dart
import 'package:flutter/material.dart';
import 'dart:ui';
void main() {
WidgetsFlutterBinding.ensureInitialized();
// Получаем текущее окно через PlatformDispatcher
final window = PlatformDispatcher.instance.views.first;
print(window);
}
Этот метод позволяет вам получить доступ к окну приложения независимо от наличия BuildContext
. Обратите внимание, что PlatformDispatcher.instance.views.first
вернёт первое представление, которое обычно соответствует главному окну вашего приложения.
Таким образом, вместо использования WidgetsBinding.instance.window
с BuildContext
, вы можете использовать PlatformDispatcher.instance.views.first
для получения доступа к окну приложения.
Внутри
PlatformDispatcher
список всех доступныхFlutterView
хранится в свойствеviews
, которое используется для предоставления возможности доступа к представлению без использованияBuildContext
.
Когда может отсутствовать BuildContext
? Например, в Flutter метод runApp
использует platformDispatcher.implicitView
, чтобы передать по умолчанию объект FlutterView
.
Что такое implicitView
? На самом деле, implicitView
— это объект FlutterView
с идентификатором 0 в коллекции PlatformDispatcher._views
, который также является первым элементом коллекции views
.
Таким образом, когда нет BuildContext
, можно использовать platformDispatcher.views.first
для получения экземпляра FlutterView
и миграции соответствующего instance.window
.
/// До версии 3.10
MediaQueryData.fromWindow(WidgetsBinding.instance.window)
/// После версии 3.10
MediaQueryData.fromView(WidgetsBinding.instance.platformDispatcher.views.first)
Почему не использовать объект implicitView
напрямую? Потому что implicitView
представляет собой переходное решение, и официальные лица надеются, что при работе с несколькими представлениями концепция implicitView
больше не будет использоваться. Вместо этого они хотят, чтобы приложения сами запрашивали создание окна и предоставляли представление для отрисовки.
Поэтому для управления состоянием implicitView
существует функция _implicitViewEnabled
, которая позволяет контролировать поддержку implicitView
через настройки. Это значит, что implicitView
может стать null
в будущих обновлениях, что делает его использование вне контекста нежелательным. Кроме того, эта настройка задается при вызове runApp
, поэтому она остается постоянной после запуска приложения; если она была пустой при старте, то всегда будет null
.
PlatformDispatcher.instance.views[0]
ранее всегда существовал в однопредставлении сценариях, независимо от наличия окон; в многопредставлении сценарияхPlatformDispatcher.instance.views
будут меняться вместе с окнами.Кроме того, мы обращаемся кviews
черезWidgetsBinding.instance.platformDispatcher.views
, а не напрямую черезPlatformDispatcher.instance.views
, поскольку обычно рекомендовано использовать зависимости Binding для доступа кPlatformDispatcher
.> Вместе с тем, в ситуациях, когда нет необходимости обращаться к объектуPlatformDispatcher
до вызова методовrunApp()
илиensureInitialized()
.
Кроме того, как показано на следующих рисунках, реализация кода, связанного с окном window
, внутри движка Engine
, указывает на то, что требуемое по умолчанию FlutterView
имеет идентификатор равный нулю. Именно поэтому мы используем WidgetsBinding.instance.platformDispatcher.views
для обеспечения совместимости.
![]() |
![]() |
![]() |
![]() |
---|
Итогом всего вышесказанного является замена WidgetsBinding.instance.window
на View.of(context)
. В случае наличия специфических сценариев можно использовать WidgetsBinding.instance.platformDispatcher.views
. При условии, что вы готовы принять возможные последствия, можно также воспользоваться WidgetsBinding.instance.platformDispatcher.implicitView
.Обсуждая все это подробно, главной целью было предоставить вам контекст изменения и более глубокое понимание прогресса реализации множества окон, и вероятнее всего, следующий выпуск уже будет содержать эту возможность.Дополнительные обсуждения доступны по следующим ссылкам:
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )