我正在使用 youtube_player_flutter 包播放 youtube 嵌入式视频。我遇到了包裹问题。根据我的理解,我使用 init 方法、分配控制器的函数等几乎都尝试了所有方法,但都没有奏效。
问题
YoutubeController 只接受一个 id 并且我有一个 URL 列表,所以我在 listview builder 方法中分配了控制器,并根据索引分配了 videoId。问题是当应用程序启动时它工作正常,但是如果我热重载或保存播放按钮会变成无限加载,如果我再次热重载它会停止并返回播放按钮。如果我播放视频,播放器会播放,但仍显示缩略图。如果热重新加载,缩略图将更改为正在播放的视频。初次启动后,如果我热重载或保存。它总是需要热重载来改变状态。
使用 onEnd() 属性将视频重置为初始状态,即带有播放按钮的视频缩略图。但是使用
onEnded: () {_ytController.reset(); }
显示视频缩略图的无限加载。PS。状态仅在热重载后更改。播放视频时,我不想显示标题容器,因此我使用
_isPlaying
bool 来更改状态。该值正在更改,但即使使用setstate()
. 我认为它需要再次重建。元数据标题不显示,但在分配控制器时有效
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,
),
),
),
),
],
),
);
},
),
),
);
}
}