flutter - 当我使用 youtube_player_flutter 和 carousel_slider 包时,Youtube 播放器在 Flutter / Dart 应用程序中不起作用:
问题描述
我在 Flutter / Dart 中使用以下 youtube_player_flutter 和 carousel_slider 包:
https://pub.dev/packages/youtube_player_flutter
https://pub.dev/packages/carousel_slider
我已经在视频预览屏幕上设置了它们,但是当我使用 carousel_slider 从 youtube 视频导航到另一个 youtube 视频屏幕时,在控制台面板中出现以下错误:
W/ContentCatcher(17665): Failed to notify a WebView
E/flutter (17665): [ERROR:flutter/lib/ui/ui_dart_state.cc(186)] Unhandled Exception: MissingPluginException(No implementation found for method evaluateJavascript on channel com.pichillilorenzo/flutter_inappwebview_7)
E/flutter (17665): #0 MethodChannel._invokeMethod
package:flutter/…/services/platform_channel.dart:156
E/flutter (17665): <asynchronous suspension>
E/flutter (17665): #1 InAppWebViewController.evaluateJavascript
package:flutter_inappwebview/…/in_app_webview/in_app_webview_controller.dart:1375
E/flutter (17665): <asynchronous suspension>
我有 10 MB/s 的网速,所以我 100% 确定这不是网速/网络问题。
Youtube 视频网址是https://www.youtube.com/watch?v=ZN_XrB_St-8
请找到随附的应用程序屏幕截图。请检查问题并建议我如何解决它。非常感谢。期待听到你的声音。
解决方案
下面是我们使用这两个包的预览屏幕的完整代码:
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:carousel_slider/carousel_slider.dart';
import 'package:videoproject/screens/PhotoEnlargeViewScreen.dart';
import 'package:videoproject/vendor/Constants.dart';
import 'package:videoproject/vendor/Masterfunctions.dart';
import 'package:videoproject/widgets/CustomLoaderWidget.dart';
import 'package:videoproject/widgets/CustomerLoaderCircularProgressIndicatorWidget.dart';
import 'package:videoproject/widgets/ShowAppDialog.dart';
import 'package:youtube_player_flutter/youtube_player_flutter.dart';
class PhotosViewerScreen extends StatefulWidget {
final List filesPathList;
final int fileIndex;
PhotosViewerScreen({required this.filesPathList, this.fileIndex = 0});
@override
_PhotosViewerScreenState createState() => _PhotosViewerScreenState();
}
class _PhotosViewerScreenState extends State<PhotosViewerScreen> {
MasterFunctions mf = MasterFunctions();
CarouselController _carouselController = CarouselController();
List _filesPathList = [];
int? _activeFileIndex;
String? _activeFilePath;
bool _isPlayingVideo = false;
bool _isLoading = false;
YoutubePlayerController? _yTPlayerController;
@override
void initState() {
_filesPathList = widget.filesPathList;
_activeFileIndex = widget.fileIndex;
_activeFilePath = widget.filesPathList[widget.fileIndex];
if (_activeFilePath.toString().indexOf('youtube.com') != -1) {
// video case
_isPlayingVideo = true;
_videoinit();
} else {
// photo case
_isPlayingVideo = false;
}
//
super.initState();
}
customcallbackFunction(
int currentPhotoIndex, CarouselPageChangedReason reason) async {
_activeFileIndex = currentPhotoIndex;
_activeFilePath = _filesPathList[_activeFileIndex as int];
print("_activeFilePath: $_activeFilePath");
//
if (_activeFilePath.toString().indexOf('youtube.com') != -1) {
// video case
_isPlayingVideo = true;
_videoinit();
} else {
// photo case
_isPlayingVideo = false;
}
if (mounted) {
setState(() {});
}
}
_videoinit() {
String videoId;
videoId = YoutubePlayer.convertUrlToId(_activeFilePath.toString())!;
if (_yTPlayerController == null) {
_yTPlayerController = YoutubePlayerController(
initialVideoId: videoId, //'iLnmTe5Q2Qw',
flags: YoutubePlayerFlags(
autoPlay: true,
// mute: true,
),
);
if (mounted) {
setState(() {});
}
} else {
// already initialized a video and wants to play next video
// dispose last video if playing
final _oldYTPlayerController = _yTPlayerController;
WidgetsBinding.instance!.addPostFrameCallback((_) async {
_oldYTPlayerController!.dispose();
// Initing new controller
_yTPlayerController = YoutubePlayerController(
initialVideoId: videoId, //'iLnmTe5Q2Qw',
flags: YoutubePlayerFlags(
autoPlay: true,
// mute: true,
),
);
if (mounted) {
setState(() {});
}
});
//
if (mounted) {
setState(() {
_yTPlayerController = null;
});
}
}
}
@override
Widget build(BuildContext context) {
final double heightWrapper = MediaQuery.of(context).size.height;
bool isPortrait =
(MediaQuery.of(context).orientation == Orientation.portrait);
return CustomLoaderWidget(
isLoadingStatus: _isLoading,
appBodyWidget: Scaffold(
appBar: (_isPlayingVideo == false ||
(_isPlayingVideo == true && isPortrait == true))
? AppBar(
title: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: [
Text(
(widget.filesPathList.length > 1)
? 'Photos/Videos Preview'
: "${(_activeFilePath.toString().indexOf('youtube.com') != -1) ? 'Video' : 'Photo'} Preview",
style: Theme.of(context).appBarTheme.textTheme!.headline1,
),
if (widget.filesPathList.length > 1)
Text(
// "${(_activeFilePath.toString().indexOf('youtube.com') != -1) ? 'Video' : 'Photo' } ${_activeFileIndex! + 1} out of ${widget.filesPathList.length}",
"Showing ${_activeFileIndex! + 1} out of ${widget.filesPathList.length}",
style: Theme.of(context).textTheme.bodyText2,
),
],
),
actions: [
IconButton(
icon:
Icon(Icons.help, color: Theme.of(context).primaryColor),
onPressed: () {
ShowAppDialog.showAlertDialog(
context: context,
titleText: 'Tips',
subtitleText:
'- Swipe left or right to see more photos/videos.\n- Tap on photo to see enlarge view.\n- Rotate phone horizontally to see video on full screen.');
},
),
],
)
: null,
body: Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
// color: Colors.black,
),
child: Center(
child: (_filesPathList.length > 0)
? CarouselSlider(
carouselController: _carouselController,
options: CarouselOptions(
height: heightWrapper,
viewportFraction: 1.0,
initialPage: _activeFileIndex!,
enableInfiniteScroll: false,
enlargeCenterPage: false,
onPageChanged: customcallbackFunction,
// autoPlay: false,
),
items: _filesPathList.map((mapFilePath) {
if (_activeFilePath.toString().indexOf('youtube.com') !=
-1) {
// video case
if (_yTPlayerController != null) {
return Container(
// color: Colors.black,
padding: EdgeInsets.symmetric(
vertical: (isPortrait)
? (heightWrapper * 0.20)
: 0.0),
child: Hero(
tag: _activeFilePath.toString(),
child: YoutubePlayer(
controller: _yTPlayerController!,
showVideoProgressIndicator: true,
progressIndicatorColor: CONST_APP_PRIMARY_COLOR,
aspectRatio: 1,
),
),
);
} else {
return Container(
width: 200.0,
height: 200.0,
child: Text('player not found'),
);
}
} else {
// photo case
return Container(
child: (mf.isValidUrl(_activeFilePath!))
? InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
PhotoEnlargeViewScreen(
photoPath: _activeFilePath!),
),
);
},
child: Hero(
tag: _activeFilePath.toString(),
child: CachedNetworkImage(
imageUrl: _activeFilePath!,
placeholder: (context, url) =>
new CustomerLoaderCircularProgressIndicatorWidget(),
errorWidget: (context, url, error) =>
new Icon(Icons.error),
),
),
)
: Image.asset(
'assets/images/person04.jpg',
alignment: Alignment.center,
fit: BoxFit.cover,
),
);
}
}).toList(),
)
: Container(
child: CustomerLoaderCircularProgressIndicatorWidget(),
),
),
),
),
);
}
}
请分享您的建议,将不胜感激。非常感谢。
推荐阅读
- java - 如何在文本小部件中读取 LocalTime 变量
- pipeline - 我需要在没有 nltk 的情况下在 python 中执行 Stemming 操作。使用管道方法
- angular - 实现可重用 Angular 反应式“子表单”的正确方法
- android - Kotlin 扩展在 Firebase Crashlytics 中引发 NullPointerException
- java - Java:对象构造/初始化可以推迟吗?
- ibm-cloud - 如何更改 IBM Cloud 界面语言?
- python - 将分组条形图与截断折线图相结合
- java - 使用 JDBC 和 MongoDB 查询存储在 String 中的日期
- javascript - PyMiniRacer 将 Python 类添加到 JS 范围
- laravel - Laravel whereIn 仅返回每个项目