1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/CarGuo-GSYFlutterBook

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
Клонировать/Скачать
Flutter-310Win.md 16 КБ
Копировать Редактировать Web IDE Исходные данные Просмотреть построчно История
Отправлено 10.03.2025 00:06 5767d61

Адаптация Flutter 3.10: Устаревание единого экземпляра окна, погружение в View.of и PlatformDispatcher

После выпуска 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

Перейдём к первому случаю — когда существует 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`.

![image](http://img.cdn.guoshuyu.cn/20230517_310/image2.png)

Краткий вывод: в случае существования `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 )

Вы можете оставить комментарий после Вход в систему

1
https://api.gitlife.ru/oschina-mirror/CarGuo-GSYFlutterBook.git
git@api.gitlife.ru:oschina-mirror/CarGuo-GSYFlutterBook.git
oschina-mirror
CarGuo-GSYFlutterBook
CarGuo-GSYFlutterBook
master