Flutter视频播放主题定制插件video_js_themed的使用

Flutter视频播放主题定制插件video_js_themed的使用

Flutter 插件 video_js_themed 用于在 Flutter Web 应用中集成 Video.js 播放器,并支持主题定制。

演示图

安装

将插件添加到项目的 pubspec.yaml 文件中:

dependencies:
  video_js_themed: ^0.0.1

Web 配置

在 Web 部分的 index.html 文件中包含 Video.js 和主题库:

<link href="https://unpkg.com/video.js@7.20.2/dist/video-js.min.css" rel="stylesheet">
<link href="https://unpkg.com/@videojs/themes@1/dist/fantasy/index.css" rel="stylesheet">
<script src="https://unpkg.com/video.js@7.20.2/dist/video.min.js"></script>

示例代码

以下是一个完整的示例代码,展示了如何使用 video_js_themed 插件来创建一个带有主题的视频播放器。

import 'package:flutter/material.dart';
import 'package:videojs_themed/videojs.dart';

void main() {
  // 初始化 JavaScript 回调
  VideoJsResults().init();
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Video JS with Theme Demo',
      home: const OptionsPage(),
    );
  }
}

class OptionsPage extends StatefulWidget {
  const OptionsPage({Key? key}) : super(key: key);

  [@override](/user/override)
  OptionsPageState createState() => OptionsPageState();
}

class OptionsPageState extends State<OptionsPage> {
  bool? controls = true;
  bool? loop = false;
  bool? muted = false;
  String? aspectRatio = '16:9';
  bool? fluid = false;
  bool? fill = false;
  String? language = 'en';
  bool? liveUI = false;
  String? notSupportedMessage = 'this movie type not supported';
  String? source = 'https://multiplatform-f.akamaihd.net/i/multi/will/bunny/big_buck_bunny_,640x360_400,640x360_700,640x360_1000,950x540_1500,.f4v.csmil/master.m3u8';
  String? sourceType = 'application/x-mpegURL';
  List<double>? playbackRates = [];
  bool? preferFullWindow = false;
  bool? responsive = false;
  bool? suppressNotSupportedError = false;

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('videoJs Options'),
      ),
      body: ListView(
        children: [
          CheckboxListTile(
            title: const Text('Controls'),
            value: controls,
            onChanged: (val) {
              setState(() {
                controls = val;
              });
            },
            controlAffinity: ListTileControlAffinity.leading,
          ),
          CheckboxListTile(
            title: const Text('Loop'),
            value: loop,
            onChanged: (val) {
              setState(() {
                loop = val;
              });
            },
            controlAffinity: ListTileControlAffinity.leading,
          ),
          CheckboxListTile(
            title: const Text('Muted'),
            value: muted,
            onChanged: (val) {
              setState(() {
                muted = val;
              });
            },
            controlAffinity: ListTileControlAffinity.leading,
          ),
          CheckboxListTile(
            title: const Text('Fluid'),
            value: fluid ?? false,
            onChanged: (val) {
              setState(() {
                fluid = val;
              });
            },
            controlAffinity: ListTileControlAffinity.leading,
          ),
          CheckboxListTile(
            title: const Text('Fill'),
            value: fill ?? false,
            onChanged: (val) {
              setState(() {
                fill = val;
              });
            },
            controlAffinity: ListTileControlAffinity.leading,
          ),
          CheckboxListTile(
            title: const Text('Live UI'),
            value: liveUI ?? false,
            onChanged: (val) {
              setState(() {
                liveUI = val;
              });
            },
            controlAffinity: ListTileControlAffinity.leading,
          ),
          CheckboxListTile(
            title: const Text('Prefer Full Window'),
            value: preferFullWindow ?? false,
            onChanged: (val) {
              setState(() {
                preferFullWindow = val;
              });
            },
            controlAffinity: ListTileControlAffinity.leading,
          ),
          CheckboxListTile(
            title: const Text('Responsive'),
            value: responsive ?? false,
            onChanged: (val) {
              setState(() {
                responsive = val;
              });
            },
            controlAffinity: ListTileControlAffinity.leading,
          ),
          CheckboxListTile(
            title: const Text('Suppress Not Supported Error'),
            value: suppressNotSupportedError,
            onChanged: (val) {
              setState(() {
                suppressNotSupportedError = val;
              });
            },
            controlAffinity: ListTileControlAffinity.leading,
          ),
          ListTile(
            leading: const Text('Aspect Ratio'),
            title: TextField(
              controller: TextEditingController(text: aspectRatio ?? '16:9'),
              onChanged: (val) {
                aspectRatio = val;
              },
            ),
          ),
          ListTile(
            leading: const Text('Language'),
            title: TextField(
              controller: TextEditingController(text: language),
              onChanged: (val) {
                language = val;
              },
            ),
          ),
          ListTile(
            leading: const Text('Not Supported Message'),
            title: TextField(
              controller: TextEditingController(text: notSupportedMessage),
              onChanged: (val) {
                notSupportedMessage = val;
              },
            ),
          ),
          ListTile(
            leading: const Text('Source'),
            title: TextField(
              controller: TextEditingController(text: source),
              onChanged: (val) {
                source = val;
              },
            ),
          ),
          ListTile(
            leading: const Text('Source Type'),
            title: TextField(
              controller: TextEditingController(text: sourceType),
              onChanged: (val) {
                sourceType = val;
              },
            ),
          ),
          ListTile(
            leading: const Text('Playback Rates'),
            title: TextField(
              controller: TextEditingController(text: '1,2,3'),
              onChanged: (val) {
                playbackRates!.clear();
                val.split(',').forEach((element) {
                  if (element != '') {
                    playbackRates!.add(double.parse(element));
                  }
                });
              },
            ),
          ),
          const SizedBox(height: 30),
          ElevatedButton(
            onPressed: () {
              Navigator.push(
                context,
                MaterialPageRoute(
                  builder: (context) => MyHomePage(
                    videoJsOptions: VideoJsOptions(
                      controls: controls,
                      loop: loop,
                      muted: muted,
                      aspectRatio: aspectRatio,
                      fluid: fluid,
                      fill: fill,
                      language: language,
                      liveui: liveUI,
                      notSupportedMessage: notSupportedMessage,
                      playbackRates: playbackRates,
                      preferFullWindow: preferFullWindow,
                      responsive: responsive,
                      sources: [Source(source!, sourceType!)],
                      suppressNotSupportedError: suppressNotSupportedError,
                    ),
                  ),
                ),
              );
            },
            child: const Text(
              'Navigate to video page',
              style: TextStyle(color: Colors.white),
            ),
          ),
          const SizedBox(height: 30),
        ],
      ),
    );
  }
}

class MyHomePage extends StatefulWidget {
  final VideoJsOptions videoJsOptions;

  const MyHomePage({Key? key, required this.videoJsOptions}) : super(key: key);

  [@override](/user/override)
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  String playerId = 'videoId';
  TextEditingController videoSourceController = TextEditingController();
  TextEditingController videoTypeController = TextEditingController();
  late VideoJsController videoJsController;

  [@override](/user/override)
  void initState() {
    super.initState();
    videoSourceController.text = 'https://multiplatform-f.akamaihd.net/i/multi/will/bunny/big_buck_bunny_,640x360_400,640x360_700,640x360_1000,950x540_1500,.f4v.csmil/master.m3u8';
    videoTypeController.text = 'application/x-mpegURL';
    videoJsController = VideoJsController(
      playerId,
      videoJsOptions: widget.videoJsOptions,
      qualitySelector: true,
    );
  }

  [@override](/user/override)
  void dispose() {
    super.dispose();
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('videojs with theme example'),
      ),
      body: SingleChildScrollView(
        child: Padding(
          padding: const EdgeInsets.all(15),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.center,
            children: [
              Row(
                mainAxisSize: MainAxisSize.max,
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  VideoJsWidget(
                    videoJsController: videoJsController,
                    height: MediaQuery.of(context).size.width / 2.5,
                    width: MediaQuery.of(context).size.width / 1.5,
                    theme: 'vjs-theme-fantasy',
                  )
                ],
              ),
              const SizedBox(height: 100),
              Row(
                mainAxisSize: MainAxisSize.max,
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  SizedBox(
                    width: 200,
                    height: 50,
                    child: TextField(
                      controller: videoSourceController,
                      decoration: const InputDecoration(hintText: 'video'),
                    ),
                  ),
                  const SizedBox(width: 10),
                  SizedBox(
                    width: 100,
                    height: 50,
                    child: TextField(
                      controller: videoTypeController,
                      decoration: const InputDecoration(hintText: 'type'),
                    ),
                  ),
                  const SizedBox(width: 15),
                  ElevatedButton(
                    onPressed: () {
                      videoJsController.setSRC(
                        videoSourceController.text.toString(),
                        type: videoTypeController.text.toString(),
                      );
                    },
                    child: const Text(
                      'Set source',
                      style: TextStyle(color: Colors.white),
                    ),
                  ),
                ],
              ),
              const SizedBox(height: 50),
              Row(
                mainAxisSize: MainAxisSize.max,
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  ElevatedButton(
                    onPressed: () {
                      videoJsController.dispose();
                    },
                    child: const Text(
                      'Dispose',
                      style: TextStyle(color: Colors.white),
                    ),
                  ),
                  const SizedBox(width: 5),
                  ElevatedButton(
                    onPressed: () {
                      videoJsController.play();
                    },
                    child: const Text(
                      'Play',
                      style: TextStyle(color: Colors.white),
                    ),
                  ),
                  const SizedBox(width: 5),
                  ElevatedButton(
                    onPressed: () {
                      videoJsController.pause();
                    },
                    child: const Text(
                      'Pause',
                      style: TextStyle(color: Colors.white),
                    ),
                  ),
                  const SizedBox(width: 5),
                  ElevatedButton(
                    onPressed: () {
                      videoJsController.isPaused((val) {
                        ScaffoldMessenger.of(context).showSnackBar(SnackBar(
                          duration: const Duration(milliseconds: 500),
                          content: Text(
                            'Pause status : $val',
                            style: const TextStyle(color: Colors.white),
                          ),
                        ));
                      });
                    },
                    child: const Text(
                      'Is pause',
                      style: TextStyle(color: Colors.white),
                    ),
                  ),
                  const SizedBox(width: 5),
                  ElevatedButton(
                    onPressed: () {
                      videoJsController.currentTime((val) {
                        ScaffoldMessenger.of(context).showSnackBar(SnackBar(
                          duration: const Duration(milliseconds: 500),
                          content: Text(
                            'Current video time : $val',
                            style: const TextStyle(color: Colors.white),
                          ),
                        ));
                      });
                    },
                    child: const Text(
                      'Current video time',
                      style: TextStyle(color: Colors.white),
                    ),
                  ),
                ],
              ),
              const SizedBox(height: 20),
              Row(
                mainAxisSize: MainAxisSize.max,
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  ElevatedButton(
                    onPressed: () {
                      videoJsController.getVolume((val) =>
                          ScaffoldMessenger.of(context).showSnackBar(SnackBar(
                            duration: const Duration(milliseconds: 500),
                            content: Text(
                              'Volume is : $val',
                              style: const TextStyle(color: Colors.white),
                            ),
                          )));
                    },
                    child: const Text(
                      'Get volume',
                      style: TextStyle(color: Colors.white),
                    ),
                  ),
                  const SizedBox(width: 5),
                  ElevatedButton(
                    onPressed: () {
                      videoJsController.setVolume('0.5');
                    },
                    child: const Text(
                      'Set volume to 0.5',
                      style: TextStyle(color: Colors.white),
                    ),
                  ),
                ],
              ),
              const SizedBox(height: 20),
              Row(
                mainAxisSize: MainAxisSize.max,
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  ElevatedButton(
                    onPressed: () {
                      videoJsController.toggleMute();
                    },
                    child: const Text(
                      'Toggle mute',
                      style: TextStyle(color: Colors.white),
                    ),
                  ),
                  const SizedBox(width: 5),
                  ElevatedButton(
                    onPressed: () {
                      videoJsController.isMute((val) {
                        ScaffoldMessenger.of(context).showSnackBar(SnackBar(
                          duration: const Duration(milliseconds: 500),
                          content: Text(
                            'Mute status : $val',
                            style: const TextStyle(color: Colors.white),
                          ),
                        ));
                      });
                    },
                    child: const Text(
                      'Mute status',
                      style: TextStyle(color: Colors.white),
                    ),
                  ),
                ],
              ),
              const SizedBox(height: 20),
              Row(
                mainAxisSize: MainAxisSize.max,
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  ElevatedButton(
                    onPressed: () {
                      videoJsController.toggleFullScreen();
                    },
                    child: const Text(
                      'Toggle full screen',
                      style: TextStyle(color: Colors.white),
                    ),
                  ),
                  const SizedBox(width: 5),
                  ElevatedButton(
                    onPressed: () {
                      videoJsController.isFullScreen((val) {
                        ScaffoldMessenger.of(context).showSnackBar(SnackBar(
                          duration: const Duration(milliseconds: 500),
                          content: Text(
                            'Full screen status : $val',
                            style: const TextStyle(color: Colors.white),
                          ),
                        ));
                      });
                    },
                    child: const Text(
                      'Full screen status',
                      style: TextStyle(color: Colors.white),
                    ),
                  ),
                ],
              ),
              const SizedBox(height: 20),
              Row(
                mainAxisSize: MainAxisSize.max,
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  ElevatedButton(
                    onPressed: () {
                      videoJsController.requestFullScreen();
                    },
                    child: const Text(
                      'Request full screen',
                      style: TextStyle(color: Colors.white),
                    ),
                  ),
                  const SizedBox(width: 5),
                  ElevatedButton(
                    onPressed: () {
                      videoJsController.exitFullScreen();
                    },
                    child: const Text(
                      'Exit full screen',
                      style: TextStyle(color: Colors.white),
                    ),
                  ),
                ],
              ),
              const SizedBox(height: 20),
              Row(
                mainAxisSize: MainAxisSize.max,
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  ElevatedButton(
                    onPressed: () {
                      videoJsController.setCurrentTime('100');
                    },
                    child: const Text(
                      'Set video time to 100 sec',
                      style: TextStyle(color: Colors.white),
                    ),
                  ),
                  const SizedBox(width: 5),
                  ElevatedButton(
                    onPressed: () {
                      videoJsController.durationTime((val) {
                        ScaffoldMessenger.of(context).showSnackBar(SnackBar(
                          duration: const Duration(milliseconds: 500),
                          content: Text(
                            'Duration time : $val',
                            style: const TextStyle(color: Colors.white),
                          ),
                        ));
                      });
                    },
                    child: const Text(
                      'Duration',
                      style: TextStyle(color: Colors.white),
                    ),
                  ),
                ],
              ),
              const SizedBox(height: 20),
              Row(
                mainAxisSize: MainAxisSize.max,
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  ElevatedButton(
                    onPressed: () {
                      videoJsController.remainTime((val) {
                        ScaffoldMessenger.of(context).showSnackBar(SnackBar(
                          duration: const Duration(milliseconds: 500),
                          content: Text(
                            'Remain time : $val',
                            style: const TextStyle(color: Colors.white),
                          ),
                        ));
                      });
                    },
                    child: const Text(
                      'Remain time',
                      style: TextStyle(color: Colors.white),
                    ),
                  ),
                  const SizedBox(width: 5),
                  ElevatedButton(
                    onPressed: () {
                      videoJsController.bufferPercent((val) {
                        ScaffoldMessenger.of(context).showSnackBar(SnackBar(
                          duration: const Duration(milliseconds: 500),
                          content: Text(
                            'Buffer percent : $val',
                            style: const TextStyle(color: Colors.white),
                          ),
                        ));
                      });
                    },
                    child: const Text(
                      'Buffer percent',
                      style: TextStyle(color: Colors.white),
                    ),
                  ),
                ],
              ),
              const SizedBox(height: 20),
              Row(
                mainAxisSize: MainAxisSize.max,
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  ElevatedButton(
                    onPressed: () {
                      videoJsController.setPoster(
                        'https://file-examples-com.github.io/uploads/2017/10/file_example_JPG_100kB.jpg',
                      );
                    },
                    child: const Text(
                      'Set video poster',
                      style: TextStyle(color: Colors.white),
                    ),
                  ),
                  const SizedBox(width: 5),
                  ElevatedButton(
                    onPressed: () {
                      videoJsController.getPoster((val) {
                        ScaffoldMessenger.of(context).showSnackBar(SnackBar(
                          duration: const Duration(milliseconds: 500),
                          content: Text(
                            'Video poster : $val',
                            style: const TextStyle(color: Colors.white),
                          ),
                        ));
                      });
                    },
                    child: const Text(
                      'Get video poster',
                      style: TextStyle(color: Colors.white),
                    ),
                  ),
                ],
              ),
              const SizedBox(height: 50),
            ],
          ),
        ),
      ),
    );
  }
}

更多关于Flutter视频播放主题定制插件video_js_themed的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter视频播放主题定制插件video_js_themed的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


video_js_themed 是一个 Flutter 插件,用于在应用中播放视频,并提供了主题定制的功能。它基于 video_player 插件,并添加了对主题的自定义支持,使开发者能够更容易地调整视频播放器的外观和感觉。

安装插件

首先,你需要在 pubspec.yaml 文件中添加 video_js_themed 插件的依赖:

dependencies:
  flutter:
    sdk: flutter
  video_js_themed: ^1.0.0  # 请使用最新版本

然后运行 flutter pub get 来安装插件。

基本用法

  1. 导入插件

    在你的 Dart 文件中导入 video_js_themed 插件:

    import 'package:video_js_themed/video_js_themed.dart';
    
  2. 创建 VideoPlayerController

    你需要创建一个 VideoPlayerController 来控制视频的播放。你可以从网络、本地文件或资产中加载视频。

    final VideoPlayerController controller = VideoPlayerController.network(
      'https://www.example.com/sample.mp4',
    );
    
  3. 初始化控制器

    在播放视频之前,你需要初始化控制器:

    await controller.initialize();
    
  4. 使用 VideoJsThemed 组件

    使用 VideoJsThemed 组件来显示视频播放器,并应用自定义主题:

    VideoJsThemed(
      controller: controller,
      theme: VideoTheme(
        playButtonColor: Colors.blue,
        progressBarColor: Colors.red,
        // 其他主题属性
      ),
    )
    

自定义主题

VideoJsThemed 提供了多种主题属性,允许你自定义视频播放器的外观。以下是一些常用的主题属性:

  • playButtonColor: 播放按钮的颜色。
  • progressBarColor: 进度条的颜色。
  • backgroundColor: 播放器的背景颜色。
  • textColor: 文本颜色(如时间显示)。
  • controlBarColor: 控制条的颜色。
  • fullscreenButtonColor: 全屏按钮的颜色。

你可以根据需要调整这些属性来创建符合你应用风格的主题。

控制视频播放

你可以通过 VideoPlayerController 来控制视频的播放、暂停、停止等操作:

controller.play();  // 播放视频
controller.pause(); // 暂停视频
controller.seekTo(Duration(seconds: 10)); // 跳转到指定时间

示例代码

以下是一个完整的示例代码,展示了如何使用 video_js_themed 插件来播放视频并应用自定义主题:

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

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Video.js Themed Example',
      home: VideoPlayerScreen(),
    );
  }
}

class VideoPlayerScreen extends StatefulWidget {
  [@override](/user/override)
  _VideoPlayerScreenState createState() => _VideoPlayerScreenState();
}

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

  [@override](/user/override)
  void initState() {
    super.initState();
    _controller = VideoPlayerController.network(
      'https://www.example.com/sample.mp4',
    )..initialize().then((_) {
        setState(() {});
      });
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Video.js Themed Example'),
      ),
      body: Center(
        child: _controller.value.isInitialized
            ? VideoJsThemed(
                controller: _controller,
                theme: VideoTheme(
                  playButtonColor: Colors.blue,
                  progressBarColor: Colors.red,
                  backgroundColor: Colors.black,
                  textColor: Colors.white,
                  controlBarColor: Colors.grey[800]!,
                  fullscreenButtonColor: Colors.white,
                ),
              )
            : CircularProgressIndicator(),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          setState(() {
            _controller.value.isPlaying
                ? _controller.pause()
                : _controller.play();
          });
        },
        child: Icon(
          _controller.value.isPlaying ? Icons.pause : Icons.play_arrow,
        ),
      ),
    );
  }

  [@override](/user/override)
  void dispose() {
    super.dispose();
    _controller.dispose();
  }
}
回到顶部