cupertino_progress_bar.dart 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. import 'package:flutter/material.dart';
  2. import 'package:flutter/widgets.dart';
  3. import 'package:video_player/video_player.dart';
  4. class CupertinoVideoProgressBar extends StatefulWidget {
  5. final VideoPlayerController controller;
  6. final VideoProgressColors colors;
  7. final Function() onDragStart;
  8. final Function() onDragEnd;
  9. final Function() onDragUpdate;
  10. CupertinoVideoProgressBar(this.controller, {
  11. VideoProgressColors colors,
  12. this.onDragEnd,
  13. this.onDragStart,
  14. this.onDragUpdate,
  15. })
  16. : colors = colors ?? new VideoProgressColors();
  17. @override
  18. _VideoProgressBarState createState() {
  19. return new _VideoProgressBarState();
  20. }
  21. }
  22. class _VideoProgressBarState extends State<CupertinoVideoProgressBar> {
  23. VoidCallback listener;
  24. bool _controllerWasPlaying = false;
  25. _VideoProgressBarState() {
  26. listener = () {
  27. setState(() {});
  28. };
  29. }
  30. VideoPlayerController get controller => widget.controller;
  31. @override
  32. void initState() {
  33. super.initState();
  34. controller.addListener(listener);
  35. }
  36. @override
  37. void deactivate() {
  38. controller.removeListener(listener);
  39. super.deactivate();
  40. }
  41. @override
  42. Widget build(BuildContext context) {
  43. void seekToRelativePosition(Offset globalPosition) {
  44. final RenderBox box = context.findRenderObject();
  45. final Offset tapPos = box.globalToLocal(globalPosition);
  46. final double relative = tapPos.dx / box.size.width;
  47. final Duration position = controller.value.duration * relative;
  48. controller.seekTo(position);
  49. }
  50. return new GestureDetector(
  51. child: (controller.value.isErroneous)
  52. ? new Text(controller.value.errorDescription)
  53. : new Center(
  54. child: new Container(
  55. height: MediaQuery
  56. .of(context)
  57. .size
  58. .height,
  59. width: MediaQuery
  60. .of(context)
  61. .size
  62. .width,
  63. color: Colors.transparent,
  64. child: new CustomPaint(
  65. painter: new _ProgressBarPainter(
  66. controller.value,
  67. widget.colors,
  68. ),
  69. ),
  70. ),
  71. ),
  72. onHorizontalDragStart: (DragStartDetails details) {
  73. if (!controller.value.initialized) {
  74. return;
  75. }
  76. _controllerWasPlaying = controller.value.isPlaying;
  77. if (_controllerWasPlaying) {
  78. controller.pause();
  79. }
  80. if (widget.onDragStart != null) {
  81. widget.onDragStart();
  82. }
  83. },
  84. onHorizontalDragUpdate: (DragUpdateDetails details) {
  85. if (!controller.value.initialized) {
  86. return;
  87. }
  88. seekToRelativePosition(details.globalPosition);
  89. if (widget.onDragUpdate != null) {
  90. widget.onDragUpdate();
  91. }
  92. },
  93. onHorizontalDragEnd: (DragEndDetails details) {
  94. if (_controllerWasPlaying) {
  95. controller.play();
  96. }
  97. if (widget.onDragEnd != null) {
  98. widget.onDragEnd();
  99. }
  100. },
  101. onTapDown: (TapDownDetails details) {
  102. if (!controller.value.initialized) {
  103. return;
  104. }
  105. seekToRelativePosition(details.globalPosition);
  106. },
  107. );
  108. }
  109. }
  110. class _ProgressBarPainter extends CustomPainter {
  111. VideoPlayerValue value;
  112. VideoProgressColors colors;
  113. _ProgressBarPainter(this.value, this.colors);
  114. @override
  115. bool shouldRepaint(CustomPainter painter) {
  116. return true;
  117. }
  118. @override
  119. void paint(Canvas canvas, Size size) {
  120. final barHeight = 5.0;
  121. final handleHeight = 6.0;
  122. final baseOffset = size.height / 2 - barHeight / 2.0;
  123. canvas.drawRRect(
  124. new RRect.fromRectAndRadius(
  125. new Rect.fromPoints(
  126. new Offset(0.0, baseOffset),
  127. new Offset(size.width, baseOffset + barHeight),
  128. ),
  129. new Radius.circular(4.0),
  130. ),
  131. colors.disabledPaint,
  132. );
  133. if (!value.initialized) {
  134. return;
  135. }
  136. final double playedPart = value.position.inMilliseconds /
  137. value.duration.inMilliseconds *
  138. size.width;
  139. for (DurationRange range in value.buffered) {
  140. final double start = range.startFraction(value.duration) * size.width;
  141. final double end = range.endFraction(value.duration) * size.width;
  142. canvas.drawRRect(
  143. new RRect.fromRectAndRadius(
  144. new Rect.fromPoints(
  145. new Offset(start, baseOffset),
  146. new Offset(end, baseOffset + barHeight),
  147. ),
  148. new Radius.circular(4.0),
  149. ),
  150. colors.bufferedPaint,
  151. );
  152. }
  153. canvas.drawRRect(
  154. new RRect.fromRectAndRadius(
  155. new Rect.fromPoints(
  156. new Offset(0.0, baseOffset),
  157. new Offset(playedPart, baseOffset + barHeight),
  158. ),
  159. new Radius.circular(4.0),
  160. ),
  161. colors.playedPaint,
  162. );
  163. final shadowPath = new Path()
  164. ..addOval(new Rect.fromCircle(
  165. center: new Offset(playedPart, baseOffset + barHeight / 2),
  166. radius: handleHeight
  167. ));
  168. canvas.drawShadow(shadowPath, Colors.black, 0.2, false);
  169. canvas.drawCircle(
  170. new Offset(playedPart, baseOffset + barHeight / 2),
  171. handleHeight,
  172. colors.handlePaint,
  173. );
  174. }
  175. }