我正在使用 youtube_player_flutter 包來播放 youtube 嵌入的視頻。我遇到了包裹問題。根據我的理解,我使用 init 方法、分配控制器的函式等嘗試了幾乎所有方法,但均無效。
問題
YoutubeController 只需要一個 id 并且我有一個 URL 串列,所以我在 listview builder 方法中分配了控制器,并根據索引分配了 videoId。問題是當應用程式啟動時它作業正常,但如果我熱多載或保存播放按鈕變成無限加載,如果我再次熱多載它會停止并回傳播放按鈕。如果我播放視頻,播放器會播放但仍顯示縮略圖。如果熱多載,縮略圖會更改為正在播放的視頻。如果我熱重新加載或保存,初始啟動后。它總是需要熱多載來改變狀態。
使用 onEnd() 屬性將視頻重置為初始狀態,即帶有播放按鈕的視頻縮略圖。但是 using
onEnded: () {_ytController.reset(); }顯示了視頻縮略圖的無限加載。附注。只有在熱多載后狀態才會改變。播放視頻時,我不想顯示標題容器,因此我使用
_isPlayingbool 來更改狀態。該值正在發生變化,但即使使用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,
),
),
),
),
],
),
);
},
),
),
);
}
}
uj5u.com熱心網友回復:
代碼前的一些注釋)
- 不要將這個最終的 _ytController = YoutubePlayerController... 放入構建器 - 每次運行 setstate 時都重新創建所有控制器。您必須為每個視頻制作一些控制器串列并將其填充到 init override
- 重置開始,您應該使用 _ytController.seekTo 命令。
- 將您的 isPlayng 狀態保存到全域串列中并將其簽入構建器
- 只有在播放具體視頻時,我才從控制器獲得元資料標題。更好的方法 - 以前通過通常的 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,),
)
],
),
);
},
),
),
);
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/391673.html
