一、插件介绍

video_full_screen是一个专为OpenHarmony平台适配的Flutter视频播放插件,基于video_playerchewie进行定制开发,提供了完整的视频播放功能和流畅的全屏体验。该插件支持本地视频播放、在线视频流播放、播放控制、进度条拖动、全屏切换等核心功能,并针对OpenHarmony平台进行了深度优化。

核心特性:

  • 🎬 支持本地视频和网络视频播放
  • 🎛️ 完整的播放控制(播放/暂停、进度拖动、音量调节)
  • 📺 流畅的全屏切换体验
  • 📱 自动适配屏幕方向(横屏/竖屏)
  • 🎨 优雅的UI设计和交互体验
  • 🔧 针对OpenHarmony平台深度优化

二、环境要求

  • OpenHarmony:API 9 及以上版本
  • Flutter:3.0.0 及以上版本
  • 开发工具:DevEco Studio 3.0+ 或 VS Code + Flutter插件

三、插件引入与配置

由于video_full_screen是针对OpenHarmony平台的定制版本,需要通过Git方式引入依赖。请按照以下步骤进行配置:

1. 添加依赖配置

在项目的pubspec.yaml文件中,添加以下依赖配置:

dependencies:
  flutter:
    sdk: flutter
  cupertino_icons: ^1.0.2
  chewie: 1.7.5
  orientation: ^1.3.0

dependency_overrides:
  video_player:
    git:
      url: "https://atomgit.com/openharmony-tpc/flutter_packages"
      path: "packages/video_player/video_player"

2. 配置资源文件

如果需要播放本地视频,请在pubspec.yaml中添加资源文件配置:

flutter:
  uses-material-design: true
  assets:
    - assets/video1.mp4

然后在项目根目录下创建assets文件夹,并将视频文件放入其中。

3. 安装依赖

执行以下命令安装依赖:

flutter pub get

四、API使用示例

1. 基本用法

以下是video_full_screen的基本使用示例:

import 'package:flutter/material.dart';
import 'package:video_player/video_player.dart';
import 'package:chewie/chewie.dart';
import 'package:flutter/services.dart';

class VideoPlayerScreen extends StatefulWidget {
  const VideoPlayerScreen({super.key});

  
  State<VideoPlayerScreen> createState() => _VideoPlayerScreenState();
}

class _VideoPlayerScreenState extends State<VideoPlayerScreen> {
  late VideoPlayerController _controller;
  late ChewieController _chewieController;

  
  void initState() {
    super.initState();

    // 初始化视频控制器
    _controller = VideoPlayerController.asset("assets/video1.mp4");

    // 初始化Chewie控制器
    _chewieController = ChewieController(
      videoPlayerController: _controller,
      autoPlay: true,
      looping: true,
      deviceOrientationsAfterFullScreen: [
        DeviceOrientation.portraitUp,
        DeviceOrientation.portraitDown
      ],
    );

    // 初始化视频
    _controller.initialize();
  }

  
  void dispose() {
    super.dispose();
    _controller.dispose();
    _chewieController.dispose();
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('视频播放器'),
      ),
      body: Center(
        child: Chewie(
          controller: _chewieController,
        ),
      ),
    );
  }
}

2. 完整功能示例

以下是一个包含完整功能的视频播放器示例,包括自定义控制UI:

import 'dart:async';
import 'package:chewie/chewie.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:video_player/video_player.dart';

class MyVideoPlayer extends StatefulWidget {
  const MyVideoPlayer({super.key});

  
  State<MyVideoPlayer> createState() => _MyVideoPlayerState();
}

class _MyVideoPlayerState extends State<MyVideoPlayer> {
  bool _videoInit = false;
  VideoPlayerController? _controller;
  Duration _position = const Duration(seconds: 0);

  Timer? _timer;
  bool _hidePlayControl = true;
  double _playControlOpacity = 0;

  bool get _isFullScreen =>
      MediaQuery.of(context).orientation == Orientation.landscape;

  ChewieController? _chewieController;

  
  void initState() {
    _loadVideo();
    super.initState();
  }

  
  void dispose() {
    if (_controller != null) {
      _controller?.removeListener(_videoListener);
      _controller?.dispose();
      _chewieController?.dispose();
    }
    super.dispose();
  }

  void _loadVideo() {
    if (_controller != null) {
      _controller?.removeListener(_videoListener);
      _controller?.dispose();
    }

    setState(() {
      _hidePlayControl = true;
      _videoInit = false;
      _position = const Duration(seconds: 0);
    });

    // 加载本地视频
    _controller = VideoPlayerController.asset("assets/video1.mp4");

    // 加载网络视频示例
    // _controller = VideoPlayerController.networkUrl(
    //   Uri.parse('https://example.com/video.mp4'),
    // );

    _controller?.initialize().then((_) {
      setState(() {
        _videoInit = true;
      });
    });

    _controller?.addListener(_videoListener);

    _chewieController = ChewieController(
        videoPlayerController: _controller!,
        autoPlay: true,
        looping: true,
        deviceOrientationsAfterFullScreen: [
          DeviceOrientation.portraitUp,
          DeviceOrientation.portraitDown
        ]);
  }

  void _videoListener() async {
    Duration res = await _controller!.position ?? const Duration();
    if (res >= _controller!.value.duration) {
      _controller!.pause();
      _controller!.seekTo(const Duration(seconds: 0));
    }
    setState(() {
      _position = res;
    });
  }

  void _togglePlayControl() {
    setState(() {
      if (_hidePlayControl) {
        _hidePlayControl = false;
        _playControlOpacity = 1;
        _startPlayControlTimer();
      } else {
        if (_timer != null) _timer!.cancel();
        _playControlOpacity = 0;
        Future.delayed(const Duration(milliseconds: 300)).whenComplete(() {
          _hidePlayControl = true;
        });
      }
    });
  }

  void _startPlayControlTimer() {
    if (_timer != null) _timer!.cancel();
    _timer = Timer(const Duration(seconds: 3), () {
      setState(() {
        _playControlOpacity = 0;
        Future.delayed(const Duration(milliseconds: 300)).whenComplete(() {
          _hidePlayControl = true;
        });
      });
    });
  }

  void _toggleFullScreen() {
    setState(() async {
      var currentOrientation = MediaQuery.of(context).orientation;

      if (currentOrientation == Orientation.portrait) {
        await SystemChrome.setPreferredOrientations([
          DeviceOrientation.landscapeLeft,
          DeviceOrientation.landscapeRight
        ]);
      } else {
        await SystemChrome.setPreferredOrientations([
          DeviceOrientation.portraitUp,
          DeviceOrientation.portraitDown
        ]);
      }
      _startPlayControlTimer();
    });
  }

  String durationToTime(Duration duration) {
    String hours = duration.inHours.toString().padLeft(2, '0');
    String minutes =
        duration.inMinutes.remainder(60).toString().padLeft(2, '0');
    String seconds =
        duration.inSeconds.remainder(60).toString().padLeft(2, '0');
    return "$hours:$minutes:$seconds";
  }

  
  Widget build(BuildContext context) {
    return Container(
      width: _isFullScreen
          ? MediaQuery.of(context).size.height
          : MediaQuery.of(context).size.width,
      height: _isFullScreen
          ? MediaQuery.of(context).size.width
          : MediaQuery.of(context).size.width / 16 * 9,
      color: Colors.black,
      child: Stack(
        children: <Widget>[
          GestureDetector(
            onTap: () {
              _togglePlayControl();
            },
            child: _videoInit
                ? Center(
                    child: Chewie(
                      controller: _chewieController!,
                    ),
                  )
                : const Center(
                    child: SizedBox(
                      width: 20,
                      height: 20,
                      child: CircularProgressIndicator(),
                    ),
                  ),
          ),
          Positioned(
            left: 0,
            bottom: 0,
            child: Offstage(
              offstage: _hidePlayControl,
              child: AnimatedOpacity(
                opacity: _playControlOpacity,
                duration: const Duration(milliseconds: 300),
                child: Container(
                  width: _isFullScreen
                      ? MediaQuery.of(context).size.height
                      : MediaQuery.of(context).size.width,
                  height: 40,
                  decoration: const BoxDecoration(
                    gradient: LinearGradient(
                      begin: Alignment.bottomCenter,
                      end: Alignment.topCenter,
                      colors: [
                        Color.fromRGBO(0, 0, 0, .7),
                        Color.fromRGBO(0, 0, 0, .1)
                      ],
                    ),
                  ),
                  child: _videoInit
                      ? Row(
                          children: <Widget>[
                            IconButton(
                              padding: EdgeInsets.zero,
                              iconSize: 26,
                              icon: Icon(
                                _controller!.value.isPlaying
                                    ? Icons.pause
                                    : Icons.play_arrow,
                                color: Colors.white,
                              ),
                              onPressed: () {
                                setState(() {
                                  _controller!.value.isPlaying
                                      ? _controller!.pause()
                                      : _controller!.play();
                                  _startPlayControlTimer();
                                });
                              },
                            ),
                            Flexible(
                              child: VideoProgressIndicator(
                                _controller!,
                                allowScrubbing: true,
                                padding: const EdgeInsets.all(0),
                                colors: VideoProgressColors(
                                  playedColor: Theme.of(context).primaryColor,
                                  bufferedColor: const Color.fromRGBO(
                                      255, 255, 255, .5),
                                  backgroundColor: const Color.fromRGBO(
                                      255, 255, 255, .2),
                                ),
                              ),
                            ),
                            Container(
                              margin: const EdgeInsets.only(left: 10),
                              child: Text(
                                durationToTime(_position) +
                                    '/' +
                                    durationToTime(_controller!.value.duration),
                                style: const TextStyle(color: Colors.white),
                              ),
                            ),
                            IconButton(
                              padding: EdgeInsets.zero,
                              iconSize: 26,
                              icon: Icon(
                                _isFullScreen
                                    ? Icons.fullscreen_exit
                                    : Icons.fullscreen,
                                color: Colors.white,
                              ),
                              onPressed: () {
                                _toggleFullScreen();
                              },
                            ),
                          ],
                        )
                      : Container(),
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

3. 主页面集成

在主页面中集成视频播放器:

import 'package:flutter/material.dart';
import 'package:video_player/video_player.dart';
import 'package:chewie/chewie.dart';

import 'my_video_player.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'VideoPlayer Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'VideoPlayer Demo'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  
  void initState() {
    super.initState();
  }

  
  void dispose() {
    super.dispose();
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('视频播放示例'),
      ),
      body: const MyVideoPlayer(),
    );
  }
}

四、API说明

1. VideoPlayerController

  • 构造方法

    • VideoPlayerController.asset(String assetPath) - 加载本地视频
    • VideoPlayerController.networkUrl(Uri url) - 加载网络视频
  • 常用方法

    • initialize() - 初始化控制器
    • play() - 播放视频
    • pause() - 暂停视频
    • seekTo(Duration position) - 跳转到指定位置
    • setVolume(double volume) - 设置音量
    • dispose() - 释放资源

2. ChewieController

  • 构造参数
    • videoPlayerController - 视频控制器
    • autoPlay - 是否自动播放
    • looping - 是否循环播放
    • deviceOrientationsAfterFullScreen - 退出全屏后的屏幕方向
    • aspectRatio - 视频宽高比
    • showControls - 是否显示控制UI
    • customControls - 自定义控制UI

五、常见问题与解决方案

1. 视频无法播放

问题:视频加载后无法播放,显示黑屏或报错。

解决方案

  • 检查视频文件路径是否正确
  • 确保视频格式受支持(建议使用MP4格式)
  • 检查网络连接(网络视频)
  • 确认权限配置是否正确

2. 全屏切换异常

问题:全屏切换时方向不正确或布局混乱。

解决方案

  • 确保在ChewieController中正确配置deviceOrientationsAfterFullScreen
  • 检查OpenHarmony项目的权限配置
  • 更新Flutter和插件版本到最新

3. 性能问题

问题:视频播放卡顿或内存占用过高。

解决方案

  • 降低视频分辨率
  • 优化视频编码格式
  • 确保及时释放资源(调用dispose()
  • 关闭不必要的后台应用

六、总结

video_full_screen插件为Flutter开发者在OpenHarmony平台上提供了强大而易用的视频播放解决方案。通过本文的介绍,您可以轻松掌握该插件的使用方法,包括插件引入、配置、API调用和常见问题解决。

该插件不仅提供了完整的视频播放功能,还针对OpenHarmony平台进行了深度优化,确保在各种设备上都能提供流畅的播放体验。无论是开发教育类应用、娱乐类应用还是企业级应用,video_full_screen都是您的理想选择。

如果您在使用过程中遇到问题或有任何建议,欢迎加入开源鸿蒙跨平台社区与我们交流讨论!


欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐