video.dart 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. import 'dart:math';
  2. import 'package:cached_network_image/cached_network_image.dart';
  3. import 'package:flutter/material.dart';
  4. import 'package:get_it/get_it.dart';
  5. import 'package:provider/provider.dart';
  6. import 'package:sport/application.dart';
  7. import 'package:sport/bean/carousel.dart';
  8. import 'package:sport/bean/game.dart';
  9. import 'package:sport/pages/game/game_detail.dart';
  10. import 'package:sport/provider/game_model.dart';
  11. import 'package:sport/router/navigator_util.dart';
  12. import 'package:sport/widgets/image.dart';
  13. import 'package:umeng_common_sdk/umeng_common_sdk.dart';
  14. import 'package:url_launcher/url_launcher.dart';
  15. import 'package:video_player/video_player.dart';
  16. import 'package:visibility_detector/visibility_detector.dart';
  17. class VideoWidget extends StatefulWidget {
  18. final Carousel carousel;
  19. final bool autoPlay;
  20. final bool loop;
  21. const VideoWidget({Key? key, required this.carousel, this.autoPlay = false, this.loop = false}) : super(key: key);
  22. @override
  23. State<StatefulWidget> createState() => _VideoState();
  24. }
  25. class _VideoState extends State<VideoWidget> {
  26. late VideoPlayerController _videoPlayerController;
  27. double _opacity = 0.0;
  28. @override
  29. void initState() {
  30. _videoPlayerController = VideoPlayerController.network(widget.carousel.url)
  31. ..addListener(() {
  32. VideoPlayerValue value = _videoPlayerController.value;
  33. if (value.isInitialized && mounted) {
  34. setState(() {
  35. _opacity = value.isPlaying ? 0.0 : 1.0;
  36. });
  37. }
  38. })
  39. ..initialize().then((_) {
  40. setState(() {});
  41. _videoPlayerController.setLooping(widget.loop);
  42. if (widget.autoPlay) _videoPlayerController.play();
  43. });
  44. super.initState();
  45. }
  46. @override
  47. void dispose() {
  48. _videoPlayerController.dispose();
  49. super.dispose();
  50. }
  51. void _handleVisibilityChanged(VisibilityInfo info) {
  52. if (_videoPlayerController.value.isInitialized != true) return;
  53. if (!mounted) return;
  54. if (info.visibleFraction == 0) {
  55. _videoPlayerController.pause();
  56. } else {
  57. // _videoPlayerController.play();
  58. }
  59. }
  60. @override
  61. Widget build(BuildContext context) {
  62. return VisibilityDetector(
  63. key: ValueKey(widget.carousel.url),
  64. onVisibilityChanged: _handleVisibilityChanged,
  65. child: Stack(
  66. fit: StackFit.expand,
  67. children: [
  68. Center(child: AspectRatio(aspectRatio: max(1.78, _videoPlayerController.value.aspectRatio), child: VideoPlayer(_videoPlayerController))),
  69. ValueListenableBuilder<VideoPlayerValue>(
  70. valueListenable: _videoPlayerController,
  71. builder: (context, v, __) {
  72. if (v.isInitialized) {
  73. return GestureDetector(
  74. behavior: HitTestBehavior.opaque,
  75. onTap: () {
  76. _videoPlayerController.pause();
  77. },
  78. child: AnimatedOpacity(
  79. duration: new Duration(seconds: 1),
  80. opacity: _opacity,
  81. child: Container(
  82. width: double.infinity,
  83. height: double.infinity,
  84. decoration: BoxDecoration(color: const Color(0xFF040404).withOpacity(.4)),
  85. child: Stack(
  86. fit: StackFit.expand,
  87. children: <Widget>[
  88. if (_opacity > 0)
  89. Center(
  90. child: Column(
  91. mainAxisSize: MainAxisSize.min,
  92. children: [
  93. Padding(
  94. padding: const EdgeInsets.all(20.0),
  95. child: InkWell(
  96. child: Image.asset(
  97. v.isPlaying ? "lib/assets/img/game_icon_suspend.png" : "lib/assets/img/game_icon_play.png",
  98. height: 50.0,
  99. ),
  100. onTap: () {
  101. if (v.isPlaying) {
  102. _videoPlayerController.pause();
  103. } else {
  104. if (_videoPlayerController.value.position.compareTo(_videoPlayerController.value.duration) == 0) {
  105. _videoPlayerController.seekTo(Duration.zero);
  106. }
  107. _videoPlayerController.play();
  108. }
  109. },
  110. ),
  111. ),
  112. if (widget.carousel.gameId > 0)
  113. InkWell(
  114. onTap: () async {
  115. GameModel gameModel = GetIt.I<GameModel>();
  116. GameInfoData? game = await gameModel.getGame(widget.carousel.gameId);
  117. if (game != null) NavigatorUtil.goPage(context, (context) => GameDetailsPage(game));
  118. UmengCommonSdk.onEvent("game_start_video", {"id": "${game?.id}"});
  119. },
  120. child: Container(
  121. child: Text(
  122. "前往运动",
  123. style: Theme.of(context).textTheme.headline6?.copyWith(fontSize: 12.0),
  124. ),
  125. decoration: BoxDecoration(borderRadius: BorderRadius.circular(100.0), color: Theme.of(context).colorScheme.secondary),
  126. padding: EdgeInsets.symmetric(horizontal: 20, vertical: 6),
  127. ),
  128. )
  129. ],
  130. ),
  131. ),
  132. ],
  133. ),
  134. ),
  135. ),
  136. );
  137. } else {
  138. if (widget.carousel.cover?.isNotEmpty == true) {
  139. return Container(
  140. width: double.infinity,
  141. child: Center(
  142. child: CachedNetworkImage(
  143. imageUrl: widget.carousel.cover!,
  144. fit: BoxFit.fitWidth,
  145. ),
  146. ),
  147. );
  148. }
  149. return Center(child: CircularProgressIndicator());
  150. }
  151. }),
  152. ],
  153. ),
  154. );
  155. }
  156. }