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

OSCHINA-MIRROR/CarGuo-GSYFlutterBook

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

1. Введение

Уверены, что те, кто работал с мобильной видео-разработкой, должны знать, что реализация логики перехода от обычного воспроизведения до полноэкранного воспроизведения не является простой задачей. Например, в проекте GSYVideoPlayer используется создание нового Surface, чтобы заменить текущий способ:

  • Создается новый Surface, и соответствующее View добавляется в верхний уровень приложения DecorView;
  • При переходе в полноэкранный режим новый Surface устанавливается в Player Core;
  • Сохраняются параметры состояния воспроизведения и система поворота между двумя View;
  • При выходе из полноэкранного режима Surface удаляется из DecorView, а Surface из элемента списка передается обратно в Player Core, и состояние синхронизируется.

Иллюстрация

Конечно, различные ядра воспроизведения могут требовать выполнения дополнительных действий, но всё это становится очень простым в Flutter.

На самом деле, реализация эффекта полноэкранного перехода в Flutter очень проста, и мы подробно рассмотрим, почему это так просто в Flutter.

2. Реализация эффекта

Ниже показана реализация полноэкранного режима в Flutter, ключевой момент которой заключается в том, что нужно всего лишь прыгнуть через стек! Да, в Flutter можно легко переключаться между страницами для плавного полноэкранного перехода.Иллюстрация

Как видно из следующего кода, на странице обычного воспроизведения используется официальный плагин video_player со свойством VideoPlayer. Инициализируется VideoPlayerController для загрузки и воспроизведения нужного видео. Также здесь используется компонент Hero для создания анимационного эффекта при переходе между страницами.

```dart
@override
void initState() {
  super.initState();
  _controller = VideoPlayerController.network(
      'https://res.exexm.com/cw_145225549855002')
    ..initialize().then((_) {
      // Убедитесь, что первый кадр отображается после того, как видео было инициализировано, даже до нажатия кнопки воспроизведения.
      setState(() {});
    });
}

Container(
  height: 200,
  margin: EdgeInsets.only(
      top: MediaQuery.of(WidgetsBinding.instance.window).padding.top),
  color: Colors.black,
  child: _controller.value.initialized
      ? Hero(
          tag: "player",
          child: AspectRatio(
            aspectRatio: _controller.value.aspectRatio,
            child: VideoPlayer(_controller),
          ),
        )
      : Container(
          alignment: Alignment.center,
          child: CircularProgressIndicator(),
        ),
)

Ниже приведён код, который демонстрирует использование компонентов `Hero` и `VideoPlayer` в полноэкранном режиме для реализации анимации перехода и воспроизведения видео.

Здесь `VideoPlayerController` может быть передан через конструктор или с помощью `InheritedWidget`, главное чтобы это был тот же самый контроллер, что и в обычном режиме воспроизведения.```markdown
Container(
     color: Colors.black,
     child: Stack(
       children: <Widget>[
         Center(
           child: Hero(
             tag: "player",
             child: AspectRatio(
               aspectRatio: widget.controller.value.aspectRatio,
               child: VideoPlayer(widget.controller),
             ),
           ),
         ),
         Padding(
           padding: EdgeInsets.only(top: 25, right: 20),
           child: IconButton(
             icon: const BackButtonIcon(),
             color: Colors.white,
             onPressed: () {
               Navigator.pop(context);
             },
           ),
         )
       ],
     ),
    )

Кроме того, в Flutter можно быстро переключаться между горизонтальным и вертикальным режимами экрана с помощью метода SystemChrome.setPreferredOrientations.

И наконец, как показано ниже, можно использовать Navigator для вызова перехода страницы, чтобы обеспечить плавный переход между полноэкранным и неконфликтным режимами.

  Navigator.of(context).push(MaterialPageRoute(builder: (context) {
                    return VideoFullPage(_controller);
                  }));

Не кажется ли вам всё это простым? Для быстрого создания полноэкранной функциональности достаточно использовать VideoPlayer, Hero и Navigator. Но почему это так просто сделать в Flutter?

Реализация логики

Причины такой простоты реализации динамического полноэкранного режима заключаются в использовании плагина video_player в Flutter: внешнего текстурного объекта Texture. Так как большинство компонентов в Flutter являются платформенно-независимыми, они обычно отрисовываются непосредственно движком Flutter. Проще говоря, это значит, что **на уровне native платформы предоставляется контейнер типа Activity/ViewController, после чего внутри этого контейнера предоставляется поверхность (surface) для отрисовки пользователем движка Flutter.**Поэтому стек отрисовки компонентов в Flutter является автономным и не позволяет смешивать его напрямую с компонентами native платформы. В этом случае, чтобы включить части функциональности native платформы в Flutter, в Flutter также предоставлены механизмы PlatformView и Texture для поддержки внешних текстур.

Как показано на приведённой выше图为所示,在《Flutter 完整实战详解》 中介绍过,Flutter 的界面渲染需要经过 Widget -> RenderObject -> Layer 的过程,而在 Layer 的渲染过程中,当出现一个 TextureLayer 节点时,说明该节点使用了 Flutter 中的 Texture 控件,此时该控件的内容将由原生平台提供,并且管理 Texture 主要通过 textureId 来标识

Например, в Android native слое video_player использует exoplayer плеер, поэтому, как показано на приведённом выше рисунке, VideoPlayerController при инициализации через MethodChannel взаимодействует с native концом, готовит плеер и Surface, и возвращает соответствующий textureId обратно в Dart.

Таким образом, в предыдущих кодах, полноэкранное и неполноэкранное окна должны использовать один и тот же VideoPlayerController, чтобы гарантировать, что они имеют одинаковый textureId.

При наличии одного и того же textureId, данные будут продолжать обновляться, пока native слой не завершит воспроизведение. Даже при переключении маршрутов страницы, различные VideoPlayer внутри используют один и тот же VideoPlayerController (то есть одинаковый textureId), поэтому они будут отображать одно и то же содержание.

Как показано на следующем рисунке, этот процесс можно кратко описать следующим образом: Flutter и native платформа взаимодействуют через PixelBuffer как средство передачи данных; native слой записывает данные в PixelBuffer, а Flutter получает PixelBuffer через зарезервированный textureId и отрисовывает его с помощью движка Flutter.

Последнее, что стоит отметить, это то, что при реализации поворота страниц в iOS метод SystemChrome.setPreferredOrientations может не работать должным образом. Этот вопрос был упомянут в issues #23913 и #13238. Возможно, потребуется самостоятельно реализовать дополнительные native интерфейсы для достижения целей совместимости. Конечно, такие вопросы уже решены в сторонних библиотеках, таких как auto_orientation или orientation.

Кроме того, поворот страниц в iOS также зависит от состояния переключателя конфигурации поворота.

image

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

image

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