video: added seek by tap/drag on progress bar
This commit is contained in:
parent
b4c04d0cdf
commit
831a787ed6
3 changed files with 65 additions and 60 deletions
|
@ -27,6 +27,9 @@ class VideoControlOverlay extends StatefulWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class VideoControlOverlayState extends State<VideoControlOverlay> {
|
class VideoControlOverlayState extends State<VideoControlOverlay> {
|
||||||
|
final GlobalKey _progressBarKey = GlobalKey();
|
||||||
|
bool _playingOnDragStart = false;
|
||||||
|
|
||||||
ImageEntry get entry => widget.entry;
|
ImageEntry get entry => widget.entry;
|
||||||
|
|
||||||
Animation<double> get scale => widget.scale;
|
Animation<double> get scale => widget.scale;
|
||||||
|
@ -67,7 +70,6 @@ class VideoControlOverlayState extends State<VideoControlOverlay> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final progressBarBorderRadius = 123.0;
|
|
||||||
final mediaQuery = MediaQuery.of(context);
|
final mediaQuery = MediaQuery.of(context);
|
||||||
final viewInsets = widget.viewInsets ?? mediaQuery.viewInsets;
|
final viewInsets = widget.viewInsets ?? mediaQuery.viewInsets;
|
||||||
final viewPadding = widget.viewPadding ?? mediaQuery.viewPadding;
|
final viewPadding = widget.viewPadding ?? mediaQuery.viewPadding;
|
||||||
|
@ -87,6 +89,10 @@ class VideoControlOverlayState extends State<VideoControlOverlay> {
|
||||||
width: mediaQuery.size.width - safePadding.horizontal,
|
width: mediaQuery.size.width - safePadding.horizontal,
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: _buildProgressBar(),
|
||||||
|
),
|
||||||
|
SizedBox(width: 8),
|
||||||
OverlayButton(
|
OverlayButton(
|
||||||
scale: scale,
|
scale: scale,
|
||||||
child: value.isPlaying
|
child: value.isPlaying
|
||||||
|
@ -101,52 +107,62 @@ class VideoControlOverlayState extends State<VideoControlOverlay> {
|
||||||
tooltip: 'Play',
|
tooltip: 'Play',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(width: 8),
|
|
||||||
Expanded(
|
|
||||||
child: SizeTransition(
|
|
||||||
sizeFactor: scale,
|
|
||||||
child: BlurredRRect(
|
|
||||||
borderRadius: progressBarBorderRadius,
|
|
||||||
child: Container(
|
|
||||||
padding: EdgeInsets.symmetric(vertical: 4, horizontal: 16) + EdgeInsets.only(bottom: 16),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Colors.black26,
|
|
||||||
border: Border.all(color: Colors.white30, width: 0.5),
|
|
||||||
borderRadius: BorderRadius.all(
|
|
||||||
Radius.circular(progressBarBorderRadius),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Text(formatDuration(value.position ?? Duration.zero)),
|
|
||||||
Spacer(),
|
|
||||||
Text(formatDuration(value.duration ?? Duration.zero)),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
LinearProgressIndicator(value: progress),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SizedBox(width: 8),
|
|
||||||
OverlayButton(
|
|
||||||
scale: scale,
|
|
||||||
child: IconButton(
|
|
||||||
icon: Icon(Icons.fullscreen),
|
|
||||||
onPressed: () => _goFullscreen(),
|
|
||||||
tooltip: 'Fullscreen',
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SizeTransition _buildProgressBar() {
|
||||||
|
final progressBarBorderRadius = 123.0;
|
||||||
|
return SizeTransition(
|
||||||
|
sizeFactor: scale,
|
||||||
|
child: BlurredRRect(
|
||||||
|
borderRadius: progressBarBorderRadius,
|
||||||
|
child: GestureDetector(
|
||||||
|
onTapDown: (TapDownDetails details) {
|
||||||
|
_seek(details.globalPosition);
|
||||||
|
},
|
||||||
|
onHorizontalDragStart: (DragStartDetails details) {
|
||||||
|
_playingOnDragStart = controller.value.isPlaying;
|
||||||
|
if (_playingOnDragStart) controller.pause();
|
||||||
|
},
|
||||||
|
onHorizontalDragUpdate: (DragUpdateDetails details) {
|
||||||
|
_seek(details.globalPosition);
|
||||||
|
},
|
||||||
|
onHorizontalDragEnd: (DragEndDetails details) {
|
||||||
|
if (_playingOnDragStart) controller.play();
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
padding: EdgeInsets.symmetric(vertical: 4, horizontal: 16) + EdgeInsets.only(bottom: 16),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.black26,
|
||||||
|
border: Border.all(color: Colors.white30, width: 0.5),
|
||||||
|
borderRadius: BorderRadius.all(
|
||||||
|
Radius.circular(progressBarBorderRadius),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
key: _progressBarKey,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Text(formatDuration(value.position ?? Duration.zero)),
|
||||||
|
Spacer(),
|
||||||
|
Text(formatDuration(value.duration ?? Duration.zero)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
LinearProgressIndicator(value: progress),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
_onValueChange() => setState(() {});
|
||||||
|
|
||||||
_playPause() async {
|
_playPause() async {
|
||||||
if (value.isPlaying) {
|
if (value.isPlaying) {
|
||||||
controller.pause();
|
controller.pause();
|
||||||
|
@ -159,7 +175,10 @@ class VideoControlOverlayState extends State<VideoControlOverlay> {
|
||||||
setState(() {});
|
setState(() {});
|
||||||
}
|
}
|
||||||
|
|
||||||
_goFullscreen() {}
|
_seek(Offset globalPosition) {
|
||||||
|
final keyContext = _progressBarKey.currentContext;
|
||||||
_onValueChange() => setState(() {});
|
final RenderBox box = keyContext.findRenderObject();
|
||||||
|
final localPosition = box.globalToLocal(globalPosition);
|
||||||
|
controller.seekTo(value.duration * (localPosition.dx / box.size.width));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
16
pubspec.lock
16
pubspec.lock
|
@ -36,13 +36,6 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.2"
|
version: "1.1.2"
|
||||||
chewie:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: chewie
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "0.9.7"
|
|
||||||
collection:
|
collection:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -148,13 +141,6 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.6"
|
version: "1.1.6"
|
||||||
open_iconic_flutter:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: open_iconic_flutter
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "0.3.0"
|
|
||||||
path:
|
path:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -336,7 +322,7 @@ packages:
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.8"
|
version: "2.0.8"
|
||||||
video_player:
|
video_player:
|
||||||
dependency: transitive
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: video_player
|
name: video_player
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
|
|
|
@ -16,7 +16,6 @@ version: 1.0.0+1
|
||||||
dependencies:
|
dependencies:
|
||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
chewie: 0.9.7
|
|
||||||
collection:
|
collection:
|
||||||
draggable_scrollbar:
|
draggable_scrollbar:
|
||||||
git:
|
git:
|
||||||
|
@ -40,6 +39,7 @@ dependencies:
|
||||||
sqflite:
|
sqflite:
|
||||||
transparent_image:
|
transparent_image:
|
||||||
tuple:
|
tuple:
|
||||||
|
video_player:
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|
Loading…
Reference in a new issue