0

我正在使用 youtube_player_flutter 包播放 youtube 嵌入式视频。我遇到了包裹问题。根据我的理解,我使用 init 方法、分配控制器的函数等几乎都尝试了所有方法,但都没有奏效。

问题

  1. YoutubeController 只接受一个 id 并且我有一个 URL 列表,所以我在 listview builder 方法中分配了控制器,并根据索引分配了 videoId。问题是当应用程序启动时它工作正常,但是如果我热重载或保存播放按钮会变成无限加载,如果我再次热重载它会停止并返回播放按钮。如果我播放视频,播放器会播放,但仍显示缩略图。如果热重新加载,缩略图将更改为正在播放的视频。初次启动后,如果我热重载或保存。它总是需要热重载来改变状态。

  2. 使用 onEnd() 属性将视频重置为初始状态,即带有播放按钮的视频缩略图。但是使用onEnded: () {_ytController.reset(); }显示视频缩略图的无限加载。PS。状态仅在热重载后更改。

  3. 播放视频时,我不想显示标题容器,因此我使用_isPlayingbool 来更改状态。该值正在更改,但即使使用setstate(). 我认为它需要再次重建。

  4. 元数据标题不显示,但在分配控制器时有效init()

代码:

import 'package:flutter/material.dart';
import 'package:youtube_player_flutter/youtube_player_flutter.dart';

class HomeScreen extends StatefulWidget {
  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  // YT Controller
  // late YoutubePlayerController _youtubePlayerController;

  // Video Title
  late String videoTitle;

  // Url List
  final List<String> _videoUrlList = [
    'https://youtu.be/dWs3dzj4Wng',
    'https://youtu.be/S3npWREXr8s',
  ];

  /*
  YoutubePlayerController _ytFN({String? url}) {
    return YoutubePlayerController(
      initialVideoId: YoutubePlayer.convertUrlToId(url!)!,
      flags: const YoutubePlayerFlags(
        autoPlay: false,
        enableCaption: true,
      ),
    );
  }

  //
  @override
  void initState() {
    _ytFN(url: _videoUrlList.first);
    super.initState();
  }

  //
  @override
  void dispose() {
    _ytFN().dispose();
    _youtubePlayerController.dispose();
    super.dispose();
  }
*/
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Tubeloid'),
        centerTitle: true,
        actions: [
          IconButton(
            onPressed: () {},
            icon: const Icon(Icons.menu_outlined),
          )
        ],
      ),
      body: Padding(
        padding: const EdgeInsets.all(10.0),
        child: ListView.builder(
          itemCount: _videoUrlList.length,
          shrinkWrap: true,
          itemBuilder: (context, index) {
            ///--------------------------   ISSUE NO. 1

            // YT Controller
            final _ytController = YoutubePlayerController(
              initialVideoId:
                  YoutubePlayer.convertUrlToId(_videoUrlList[index])!,
              flags: const YoutubePlayerFlags(
                autoPlay: false,
                enableCaption: true,
                captionLanguage: 'en',
              ),
            );

            // for container visibility
            bool _isPlaying = false;

            return Padding(
              padding: const EdgeInsets.symmetric(vertical: 8.0),
              child: Stack(
                alignment: Alignment.bottomCenter,
                children: [
                  // Youtube Player
                  Container(
                    height: 220.0,
                    decoration: const BoxDecoration(
                      color: Color(0xfff5f5f5),
                      borderRadius: BorderRadius.all(Radius.circular(12)),
                    ),
                    child: ClipRRect(
                      borderRadius: const BorderRadius.all(Radius.circular(12)),
                      child: YoutubePlayer(
                        controller: _ytController
                          ..addListener(() {
                            if (_ytController.value.isPlaying) {
                              setState(() {
                                _isPlaying = true;
                              });
                            } else {
                              _isPlaying = false;
                            }
                          }),
                        showVideoProgressIndicator: true,
                        progressIndicatorColor: Colors.lightBlueAccent,
                        bottomActions: [
                          CurrentPosition(),
                          ProgressBar(isExpanded: true),
                          FullScreenButton(),
                        ],
                        onEnded: (YoutubeMetaData _md) {
                          ///---------------------------   ISSUE NO. 2
                          _ytController.reset();
                          // _ytController.seekTo(const Duration(seconds: 1));
                          // _ytController.pause();
                          _md.videoId;
                          print(_md.title);
                        },
                      ),
                    ),
                  ),

                  ///--------------------------   ISSUE NO. 3

                  // Headline
                  _isPlaying
                      ? Container()
                      : Container(
                          width: double.infinity,
                          decoration: BoxDecoration(
                            color: Colors.white.withOpacity(0.9),
                            borderRadius: const BorderRadius.only(
                              bottomRight: Radius.circular(12),
                              bottomLeft: Radius.circular(12),
                            ),
                          ),
                          child: Padding(
                            padding: const EdgeInsets.all(8.0),
                            child: Text(
                          ///--------------------------   ISSUE NO. 4
                              _ytController.metadata.title,
                              style: const TextStyle(
                                fontSize: 20.0,
                                color: Colors.black,
                              ),
                            ),
                          ),
                        ),
                ],
              ),
            );
          },
        ),
      ),
    );
  }
}
4

1 回答 1

1

代码前的一些注释)

  1. 不要将这个最终的 _ytController = YoutubePlayerController... 放入构建器中 - 每次运行 setstate 时都会重新创建所有控制器。您必须为每个视频制作一些控制器列表并将其填充到初始化覆盖中
  2. 重置开始你应该使用 _ytController.seekTo 命令。
  3. 将您的 isPlayng 状态保存到全局列表中并将其检入构建器
  4. 仅在播放具体视频时,我才从控制器获得元数据标题。所以更好的方法 - 之前通过通常的 http.get 请求为您的视频加载标题(类似于https://noembed.com/embed?url=https://www.youtube.com/watch?v=668nUCeBHyY

我的代码:

import 'package:flutter/material.dart';
import 'package:youtube_player_flutter/youtube_player_flutter.dart';

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

  @override
  _YTState createState() => _YTState();
}

class _YTState extends State<YT> {
  late String videoTitle;
  // Url List
  final List<String> _videoUrlList = [
    'https://youtu.be/dWs3dzj4Wng',
    'https://www.youtube.com/watch?v=668nUCeBHyY',
    'https://youtu.be/S3npWREXr8s',
  ];

  List <YoutubePlayerController> lYTC = [];

  Map<String, dynamic> cStates = {};

  @override
  void initState() {
    super.initState();
    fillYTlists();
  }

  fillYTlists(){
    for (var element in _videoUrlList) {
      String _id = YoutubePlayer.convertUrlToId(element)!;
      YoutubePlayerController _ytController = YoutubePlayerController(
        initialVideoId: _id,
        flags: const YoutubePlayerFlags(
          autoPlay: false,
          enableCaption: true,
          captionLanguage: 'en',
        ),
      );

      _ytController.addListener(() {
        print('for $_id got isPlaying state ${_ytController.value.isPlaying}');
        if (cStates[_id] != _ytController.value.isPlaying) {
          if (mounted) {
            setState(() {
              cStates[_id] = _ytController.value.isPlaying;
            });
          }
        }
      });

      lYTC.add(_ytController);
    }
  }

  @override
  void dispose() {
    for (var element in lYTC) {
      element.dispose();
    }
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Tubeloid'),
        centerTitle: true,
        actions: [
          IconButton(
            onPressed: () {},
            icon: const Icon(Icons.menu_outlined),
          )
        ],
      ),
      body: Padding(
        padding: const EdgeInsets.all(10.0),
        child: ListView.builder(
          itemCount: _videoUrlList.length,
          shrinkWrap: true,
          itemBuilder: (context, index) {
            YoutubePlayerController _ytController = lYTC[index];
            String _id = YoutubePlayer.convertUrlToId(_videoUrlList[index])!;
            String curState = 'undefined';
            if (cStates[_id] != null) {
              curState = cStates[_id]? 'playing':'paused';
            }
            return Padding(
              padding: const EdgeInsets.symmetric(vertical: 8.0),
              child: Stack(
                alignment: Alignment.bottomCenter,
                children: [
                  Container(
                    height: 220.0,
                    decoration: const BoxDecoration(
                      color: Color(0xfff5f5f5),
                      borderRadius: BorderRadius.all(Radius.circular(12)),
                    ),
                    child: ClipRRect(
                      borderRadius: const BorderRadius.all(Radius.circular(12)),
                      child: YoutubePlayer(
                        controller: _ytController,
                        showVideoProgressIndicator: true,
                        progressIndicatorColor: Colors.lightBlueAccent,
                        bottomActions: [
                          CurrentPosition(),
                          ProgressBar(isExpanded: true),
                          FullScreenButton(),
                        ],
                        onReady: (){
                          print('onReady for $index');
                        },
                        onEnded: (YoutubeMetaData _md) {
                          _ytController.seekTo(const Duration(seconds: 0));
                        },
                      ),
                    ),
                  ),
                  Container(
                    width: double.infinity,
                    decoration: BoxDecoration(
                      color: Colors.white.withOpacity(0.9),
                      borderRadius: const BorderRadius.only(
                        bottomRight: Radius.circular(12),
                        bottomLeft: Radius.circular(12),
                      ),
                    ),
                    child: Text(curState, textScaleFactor: 1.5,),
                  )
                ],
              ),
            );
          },
        ),
      ),
    );
  }
}
于 2021-12-24T07:23:15.257 回答