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

OSCHINA-MIRROR/CarGuo-GSYFlutterBook

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

Как часть серии статей, эта статья объясняет реализацию логики PlatformView на платформе Android с использованием официальной технической документации и объясняет, почему клавиатура PlatformView часто работает некорректно на Android.

Почему на iOS все работает более стабильно, также рассматривается в данной статье.

Ссылка на полную серию статей:

Полная серия статей по Flutter

Специальные статьи о мире Flutter

1. Почему нужен PlatformView

Исходя из концепции реализации Flutter, которая аналогична WebView на Android, Flutter преобразует дерево виджетов в текстуры и использует Skia для отрисовки компонентов. Это обеспечивает отличное кросс-платформенное взаимодействие, но создаёт проблемы совместимости.

1.1. Недостаток интеграции нативных компонентов платформы

Это как WebView: UI Flutter не превращается в Android-компоненты, а рендерится напрямую через Skia на SurfaceView.

Поэтому по умолчанию Flutter UI никогда не будет содержать нативные Android-компоненты, что делает невозможной интеграцию таких компонентов, как WebView или MapView.

Для решения этой проблемы Flutter создал логику компонента AndroidView, который позволяет разработчикам встраивать нативные Android-компоненты в Flutter UI.

1.2. Реализация AndroidViewКомпонент AndroidView требует сочетания с Flutter для полноценного отображения: в Flutter рендеринг содержимого AndroidView происходит внутри VirtualDisplays. Затем изображение, созданное в памяти VirtualDisplay, можно получить через его Surface.> VirtualDisplay - это виртуальное пространство отображения, которое используется вместе с DisplayManager. Обычно применяется при работе со вторым экраном или записи экрана. VirtualDisplay рендерит содержимое виртуального пространства отображения на Surface.

Проще говоря, содержимое нативного компонента рисуется в памяти, после чего Flutter Engine получает данные рендера компонента через соответствующий textureId и отображает их.

Используя текстуры из вывода VirtualDisplay и объединяя их с существующим деревом рендера Flutter, Flutter может включать нативные Android-компоненты в своё дерево виджетов Flutter в виде графических элементов.

1.3 Есть ли альтернативные способы реализации?

На платформе iOS вместо использования метода, аналогичного VirtualDisplay, Flutter UI разделяется на два прозрачных текстура: одна находится ниже платформенного представления iOS, другая — выше него.

Основное преимущество такого подхода заключается в том, что Flutter UI, который требуется отображать ниже платформенного представления iOS, будет рисован на нижней текстуре; а Flutter UI, который требуется отображать выше платформенного представления, будет рисован на верхней текстуре. Они просто объединяются в конце.

Обычно этот способ лучше, так как это позволяет нативному Android view напрямую добавляться в слой UI Flutter.Однако, данная модель не поддерживается на платформе Android, поскольку после рендера фрейма в iOS система отправляет обратные вызовы, такие как: когда iOS виджет смещается вниз на 2px, все остальные Flutter контролы также могут быть смещены вниз на 2px.

Но на платформе Android нет никаких системных API, связанных с этим, поэтому невозможно обеспечить синхронное рендериование. Если принудительно использовать такой подход на Android, это может привести к множеству проблем, таких как несинхронность между AndroidView и Flutter UI.

Подробнее об этом альтернативном подходе см. по адресу: https://flutter.dev/go/nshc

2. Связанные проблемы и решения

Хотя можно использовать VirtualDisplay для внедрения Android контрола в Flutter UI, использование VirtualDisplay создаёт ряд других проблем.

2.1 Обработка событий касания

По умолчанию, PlatformViews не могут получать события касания.

Это связано с тем, что AndroidView фактически рендерится внутри VirtualDisplay. Когда пользователь кликает на видимый "AndroidView", он действительно "кликает" на рендеримую текстуру Flutter. События касания пользователя передаются напрямую в Flutter View, а не в реальный AndroidView, на котором они были нажаты.

2.1.1 Решение

2.1.2 Ограничения

  • Реализация логики прямого распределения нового MotionEvent для AndroidView может привести к отправке информации о прикосновении в неправильное место, если этот View производит другие виджеты.
  • Процесс преобразования MotionEvent может вызвать потерю некоторых данных из-за различий в механизмах.

2.2 Ввод текста

Обычно AndroidView не может получить доступ к введенному тексту, так как положение VirtualDisplay всегда считается состоянием unfocused.На данный момент Android не предоставляет никаких API для динамического изменения фокуса окна Window. В Flutter окно, которое находится в состоянии focused, обычно представляет собой реальное содержание "текущего" Flutter текстурного изображения и UI, которое является видимым для пользователя.А InputConnections (механизм ввода текста в Android) обычно игнорируются в неактивном состоянии View.

2.2.1 Решение проблемы

  • Flutter переопределил метод checkInputConnectionProxy, чтобы Android воспринимал Flutter View как агента AndroidView и редактора входных данных (IME), таким образом Android сможет получать InputConnections из Flutter View и применять их к AndroidView.

  • С версии Android Q InputMethodManager (IMM) был изменён на экземпляр для каждого окна вместо глобальной единицы, поэтому простое "установление агента" больше не работает начиная с Q. Для решения этой проблемы Flutter создал подкласс Context, который возвращает контекст, аналогичный IMM в Flutter View, что позволяет использовать IMM из Flutter View как агента при запросах IMM. Это значит, что когда Android требует IMM, VirtualDisplay использует IMM из Flutter View как агента.

  • При запросе AndroidView предоставлять InputConnection, он проверяет, является ли AndroidView целью ввода. Если да, то [InputConnection из AndroidView будет получен и возвращен Android](https://github.com/flutter/engine/blob/036ddbb0ee6858ae532df82a2747aa93faee4487/shell/platform/android/io/flutter/plugin/editing/TextInputPlugin.java#L206). - Android считает Flutter View как focused и доступный, поэтому InputConnection для AndroidView может успешно быть получен и использован.

2.2.2 Ввод с клавиатуры в WebView внутри PlatformViewПеред версией Android N ввод в WebView был сложнее, так как они имеют собственные внутренние логики для создания и установки входящих соединений, которые не полностью следуют протоколу Android. В плагине flutter_webview требуется добавление других решений для активации ввода текста в WebView.- Установка прокси-вью, который прослушивает входящие соединения вместе с WebView на одном потоке. Без этой возможности WebView будет внутренне потреблять все вызовы InputConnection, не уведомляя прокси-вью Flutter.

2.2.3 Ограничения

3 ЗаключениеРеализация режима PlatformView увеличивает жизнеспособность и гибкость Flutter, но также приводит к множеству проблем, таких как темы вопросов, связанных с #webview-keyboard, #webview, #platform-views, а также, как указано в документации плагина webview_flutter:

Этот плагин использует новую механику Flutter для встраивания Android и iOS представлений. Поскольку эта механика находится в стадии предварительной версии для разработчиков, этот плагин также рассматривается как предварительная версия для разработчиков.

webview_flutter поддержка клавиатуры пока не предназначена для использования в продакшне, поскольку поддержка клавиатуры в WebView всё ещё находится в экспериментальной стадии.Теперь вы знаете, почему PlatformView в Flutter на Android сложно обеспечивать совместимость и почему связано много проблем с вводом с клавиатуры.

Наконец-то закончил двадцатую статью!(///▽///)

Рекомендованные ресурсы

Изображение

Опубликовать ( 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