我在我的应用程序项目中使用了Video Player&Chewie,效果很好,但问题是,它可以自动自动播放所有视频。但是,我想自动播放仅在视图中播放的视频,而不是一次全部播放,就像instagram一样。我确实检查了pub.dev上的文档,但找不到这种东西,因为在Flutter中我不太擅长,所以有时可能会出错。这是代码:
// import 'dart:js';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:chewie/chewie.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:flutter_rating_bar/flutter_rating_bar.dart';
import 'package:fluttershare/models/user.dart';
import 'package:fluttershare/pages/activity_feed.dart';
import 'package:fluttershare/pages/comments.dart';
import 'package:fluttershare/pages/home.dart';
import 'package:fluttershare/widgets/progress.dart';
import 'package:video_player/video_player.dart';
class Post extends StatefulWidget {
final String postId;
final String ownerId;
final String username;
final String foodname;
final String placename;
final String cityname;
final String statename;
final String mediaUrl;
final double rating;
final dynamic likes;
Post({
this.postId,
this.ownerId,
this.username,
this.foodname,
this.placename,
this.cityname,
this.statename,
this.mediaUrl,
this.rating,
this.likes,
});
factory Post.fromDocument(DocumentSnapshot doc) {
return Post(
postId: doc['postId'],
ownerId: doc['ownerId'],
username: doc['username'],
foodname: doc['foodname'],
placename: doc['placename'],
cityname: doc['cityname'],
statename: doc['statename'],
mediaUrl: doc['mediaUrl'],
rating: doc['rating'],
likes: doc['likes'],
);
}
int getLikeCount(likes) {
if (likes == null) {
return 0;
}
int count = 0;
likes.values.forEach((val) {
if (val == true) {
count += 1;
}
});
return count;
}
@override
_PostState createState() => _PostState(
postId: this.postId,
ownerId: this.ownerId,
username: this.username,
foodname: this.foodname,
placename: this.placename,
cityname: this.cityname,
statename: this.statename,
mediaUrl: this.mediaUrl,
likes: this.likes,
likeCount: getLikeCount(this.likes),
);
}
class _PostState extends State<Post> {
final String currentUserId = currentUser?.id;
final String postId;
final String ownerId;
final String username;
final String foodname;
final String placename;
final String cityname;
final String statename;
final String mediaUrl;
String rating;
int likeCount;
Map likes;
bool isLiked;
_PostState({
this.postId,
this.ownerId,
this.username,
this.foodname,
this.placename,
this.cityname,
this.statename,
this.mediaUrl,
this.rating,
this.likes,
this.likeCount,
});
buildPostHeader() {
return FutureBuilder(
future: usersRef.document(ownerId).get(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return circularProgress();
}
User user = User.fromDocument(snapshot.data);
bool isPostOwner = currentUserId == ownerId;
return ListTile(
leading: CircleAvatar(
backgroundImage: CachedNetworkImageProvider(user.photoUrl),
backgroundColor: Colors.grey,
),
title: GestureDetector(
onTap: () => showProfile(context, profileId: user.id),
child: Text(
user?.username ?? '',
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
),
),
),
trailing: isPostOwner
? IconButton(
onPressed: () => handleDeletePost(context),
icon: Icon(Icons.more_vert),
)
: Text(''),
);
},
);
}
handleDeletePost(BuildContext parentContext) {
return showDialog(
context: parentContext,
builder: (context) {
return SimpleDialog(
title: Text("Delete This Post?"),
children: <Widget>[
SimpleDialogOption(
onPressed: () {
Navigator.pop(context);
deletePost();
},
child: Text(
'Delete',
style: TextStyle(color: Colors.red),
),
),
SimpleDialogOption(
onPressed: () => Navigator.pop(context),
child: Text('Cancel')),
],
);
});
}
deletePost() async {
postsRef
.document(ownerId)
.collection('userPosts')
.document(postId)
.get()
.then((doc) {
if (doc.exists) {
doc.reference.delete();
}
});
storageRef.child("post_$postId.mp4").delete();
QuerySnapshot activityFeedSnapshot = await activityFeedRef
.document(ownerId)
.collection("feedItems")
.where('postId', isEqualTo: postId)
.getDocuments();
activityFeedSnapshot.documents.forEach((doc) {
if (doc.exists) {
doc.reference.delete();
}
});
QuerySnapshot commentsSnapshot = await commentsRef
.document(postId)
.collection('comments')
.getDocuments();
commentsSnapshot.documents.forEach((doc) {
if (doc.exists) {
doc.reference.delete();
}
});
}
VideoPlayerController _controller;
Future<void> _initializeVideoPlayerFuture;
@override
void initState() {
_controller = VideoPlayerController.network(mediaUrl);
_initializeVideoPlayerFuture = _controller.initialize().then((_) {
setState(() {});
});
_controller.setLooping(true);
_controller.setVolume(1.0);
super.initState();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
// Post Chewie Display...
buildPostImage() {
return FittedBox(
fit: BoxFit.contain,
child: mounted
? Chewie(
controller: ChewieController(
videoPlayerController: _controller,
aspectRatio: _controller.value.aspectRatio,
autoPlay: true,
looping: false,
),
)
: Container(),
);
}
handleLikePost() {
bool _isLiked = likes[currentUserId] == true;
if (_isLiked) {
postsRef
.document(ownerId)
.collection('userPosts')
.document(postId)
.updateData({'likes.$currentUserId': false});
removeLikeFromActivityFeed();
setState(() {
likeCount -= 1;
isLiked = false;
likes[currentUserId] = false;
});
} else if (!_isLiked) {
postsRef
.document(ownerId)
.collection('userPosts')
.document(postId)
.updateData({'likes.$currentUserId': true});
addLikeToActivityFeed();
setState(() {
likeCount += 1;
isLiked = true;
likes[currentUserId] = true;
});
}
}
addLikeToActivityFeed() {
bool isNotPostOwner = currentUser != ownerId;
if (isNotPostOwner) {
activityFeedRef
.document(ownerId)
.collection("feedItems")
.document(postId)
.setData({
"type": "like",
"username": currentUser.username,
"userId": currentUser.id,
"userProfileImg": currentUser.photoUrl,
"postId": postId,
"mediaUrl": mediaUrl,
"timestamp": timestamp,
});
}
}
removeLikeFromActivityFeed() {
bool isNotPostOwner = currentUser != ownerId;
if (isNotPostOwner) {
activityFeedRef
.document(ownerId)
.collection("feedItems")
.document(postId)
.get()
.then((doc) {
if (doc.exists) {
doc.reference.delete();
}
});
}
}
buildPostFooter(BuildContext context) {
return Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Padding(padding: EdgeInsets.only(top: 40.0, left: 20.0)),
GestureDetector(
onTap: handleLikePost,
child: Icon(
isLiked ? Icons.favorite : Icons.favorite_border,
size: 28.0,
color: Colors.red,
),
),
Padding(padding: EdgeInsets.only(right: 20.0)),
GestureDetector(
onTap: () => showComments(
context,
postId: postId,
ownerId: ownerId,
mediaUrl: mediaUrl,
),
child: Icon(
Icons.supervised_user_circle,
size: 28.0,
color: Colors.blueAccent,
),
),
Padding(padding: EdgeInsets.only(right: 50.0)),
Icon(Icons.location_on, color: Colors.blueAccent),
Container(
margin: EdgeInsets.only(left: 2.0, top: 5.0, right: 10.0),
child: Text("$cityname " + "$statename",
style: TextStyle(color: Colors.blueAccent)),
),
],
),
Row(
children: <Widget>[
Container(
margin: EdgeInsets.only(left: 20.0),
child: Text(
"$likeCount likes",
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
),
),
),
],
),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
margin: EdgeInsets.only(left: 20.0, top: 10.0, bottom: 5.0),
child: Text(
"$foodname ",
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
),
),
),
],
),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(padding: EdgeInsets.only(left: 20.0)),
Icon(
Icons.restaurant,
color: Colors.blueAccent,
),
Container(
color: Colors.blueAccent,
padding: EdgeInsets.all(5.0),
margin: EdgeInsets.only(left: 2.0),
child: Text(placename.toUpperCase(),
style: TextStyle(color: Colors.white)),
),
],
),
],
);
}
@override
Widget build(BuildContext context) {
isLiked = (likes[currentUserId] == true);
return Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
buildPostHeader(),
buildPostImage(),
buildPostFooter(context),
Divider(),
Padding(padding: EdgeInsets.only(bottom: 10.0)),
],
);
}
}
showComments(BuildContext context,
{String postId, String ownerId, String mediaUrl}) {
Navigator.push(context, MaterialPageRoute(builder: (context) {
return Comments(
postId: postId,
postOwnerId: ownerId,
postMediaUrl: mediaUrl,
);
}));
}
答案 0 :(得分:3)
您可以在下面复制粘贴运行完整示例代码
您可以使用软件包https://pub.dev/packages/inview_notifier_list
您可以使用VideoWidget
致电inViewState.inView('$index')
在不显示时,视频会暂停
工作演示
代码段
builder: (BuildContext context, BoxConstraints constraints) {
final InViewState inViewState =
InViewNotifierList.of(context);
inViewState.addContext(context: context, id: '$index');
return AnimatedBuilder(
animation: inViewState,
builder: (BuildContext context, Widget child) {
return VideoWidget(
play: inViewState.inView('$index'),
url:
'http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerJoyrides.mp4');
},
);
},
完整代码
import 'package:flutter/material.dart';
import 'package:inview_notifier_list/inview_notifier_list.dart';
import 'package:video_player/video_player.dart';
class VideoWidget extends StatefulWidget {
final String url;
final bool play;
const VideoWidget({Key key, @required this.url, @required this.play})
: super(key: key);
@override
_VideoWidgetState createState() => _VideoWidgetState();
}
class _VideoWidgetState extends State<VideoWidget> {
VideoPlayerController _controller;
Future<void> _initializeVideoPlayerFuture;
@override
void initState() {
super.initState();
_controller = VideoPlayerController.network(widget.url);
_initializeVideoPlayerFuture = _controller.initialize().then((_) {
// Ensure the first frame is shown after the video is initialized, even before the play button has been pressed.
setState(() {});
});
if (widget.play) {
_controller.play();
_controller.setLooping(true);
}
}
@override
void didUpdateWidget(VideoWidget oldWidget) {
if (oldWidget.play != widget.play) {
if (widget.play) {
_controller.play();
_controller.setLooping(true);
} else {
_controller.pause();
}
}
super.didUpdateWidget(oldWidget);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: _initializeVideoPlayerFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return VideoPlayer(_controller);
} else {
return Center(
child: CircularProgressIndicator(),
);
}
},
);
}
}
class VideoList extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Stack(
fit: StackFit.expand,
children: <Widget>[
InViewNotifierList(
scrollDirection: Axis.vertical,
initialInViewIds: ['0'],
isInViewPortCondition:
(double deltaTop, double deltaBottom, double viewPortDimension) {
return deltaTop < (0.5 * viewPortDimension) &&
deltaBottom > (0.5 * viewPortDimension);
},
children: List.generate(
10,
(index) {
return Container(
width: double.infinity,
height: 300.0,
alignment: Alignment.center,
margin: EdgeInsets.symmetric(vertical: 50.0),
child: LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
final InViewState inViewState =
InViewNotifierList.of(context);
inViewState.addContext(context: context, id: '$index');
return AnimatedBuilder(
animation: inViewState,
builder: (BuildContext context, Widget child) {
return VideoWidget(
play: inViewState.inView('$index'),
url:
'http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerJoyrides.mp4');
},
);
},
),
);
},
),
),
Align(
alignment: Alignment.center,
child: Container(
height: 1.0,
color: Colors.redAccent,
),
)
],
);
}
}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Expanded(child: VideoList()),
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}