Created
May 15, 2018 17:25
-
-
Save rodydavis/8560ed410d8d47427fff71a43e9a0634 to your computer and use it in GitHub Desktop.
Preview a video from view_player controller in Flutter.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:flutter/material.dart'; | |
import 'package:video_player/video_player.dart'; | |
class AspectRatioVideo extends StatefulWidget { | |
final VideoPlayerController controller; | |
AspectRatioVideo(this.controller); | |
@override | |
AspectRatioVideoState createState() => new AspectRatioVideoState(); | |
} | |
class AspectRatioVideoState extends State<AspectRatioVideo> { | |
VideoPlayerController get controller => widget.controller; | |
bool initialized = false; | |
VoidCallback listener; | |
@override | |
void initState() { | |
super.initState(); | |
listener = () { | |
if (!mounted) { | |
return; | |
} | |
if (initialized != controller.value.initialized) { | |
initialized = controller.value.initialized; | |
setState(() {}); | |
} | |
}; | |
controller.addListener(listener); | |
} | |
@override | |
Widget build(BuildContext context) { | |
if (initialized) { | |
final Size size = controller.value.size; | |
return new Center( | |
child: new AspectRatio( | |
aspectRatio: size.width / size.height, | |
child: new VideoPlayPause(controller), | |
), | |
); | |
} else { | |
return new Container(); | |
} | |
} | |
} | |
class VideoPlayPause extends StatefulWidget { | |
final VideoPlayerController controller; | |
VideoPlayPause(this.controller); | |
@override | |
State createState() { | |
return new _VideoPlayPauseState(); | |
} | |
} | |
class _VideoPlayPauseState extends State<VideoPlayPause> { | |
FadeAnimation imageFadeAnim = | |
new FadeAnimation(child: const Icon(Icons.play_arrow, size: 100.0)); | |
VoidCallback listener; | |
_VideoPlayPauseState() { | |
listener = () { | |
setState(() {}); | |
}; | |
} | |
VideoPlayerController get controller => widget.controller; | |
@override | |
void initState() { | |
super.initState(); | |
controller.addListener(listener); | |
controller.setVolume(1.0); | |
controller.play(); | |
} | |
@override | |
void deactivate() { | |
controller.setVolume(0.0); | |
controller.removeListener(listener); | |
super.deactivate(); | |
} | |
@override | |
Widget build(BuildContext context) { | |
final List<Widget> children = <Widget>[ | |
new GestureDetector( | |
child: new VideoPlayer(controller), | |
onTap: () { | |
if (!controller.value.initialized) { | |
return; | |
} | |
if (controller.value.isPlaying) { | |
imageFadeAnim = | |
new FadeAnimation(child: const Icon(Icons.pause, size: 100.0)); | |
controller.pause(); | |
} else { | |
imageFadeAnim = new FadeAnimation( | |
child: const Icon(Icons.play_arrow, size: 100.0)); | |
controller.play(); | |
} | |
}, | |
), | |
new Align( | |
alignment: Alignment.bottomCenter, | |
child: new VideoProgressIndicator( | |
controller, | |
allowScrubbing: true, | |
), | |
), | |
new Center(child: imageFadeAnim), | |
]; | |
return new Stack( | |
fit: StackFit.passthrough, | |
children: children, | |
); | |
} | |
} | |
class FadeAnimation extends StatefulWidget { | |
final Widget child; | |
final Duration duration; | |
FadeAnimation({this.child, this.duration: const Duration(milliseconds: 500)}); | |
@override | |
_FadeAnimationState createState() => new _FadeAnimationState(); | |
} | |
class _FadeAnimationState extends State<FadeAnimation> | |
with SingleTickerProviderStateMixin { | |
AnimationController animationController; | |
@override | |
void initState() { | |
super.initState(); | |
animationController = | |
new AnimationController(duration: widget.duration, vsync: this); | |
animationController.addListener(() { | |
if (mounted) { | |
setState(() {}); | |
} | |
}); | |
animationController.forward(from: 0.0); | |
} | |
@override | |
void deactivate() { | |
animationController.stop(); | |
super.deactivate(); | |
} | |
@override | |
void didUpdateWidget(FadeAnimation oldWidget) { | |
super.didUpdateWidget(oldWidget); | |
if (oldWidget.child != widget.child) { | |
animationController.forward(from: 0.0); | |
} | |
} | |
@override | |
void dispose() { | |
animationController.dispose(); | |
super.dispose(); | |
} | |
@override | |
Widget build(BuildContext context) { | |
return animationController.isAnimating | |
? new Opacity( | |
opacity: 1.0 - animationController.value, | |
child: widget.child, | |
) | |
: new Container(); | |
} | |
} | |
typedef Widget VideoWidgetBuilder( | |
BuildContext context, VideoPlayerController controller); | |
abstract class PlayerLifeCycle extends StatefulWidget { | |
final VideoWidgetBuilder childBuilder; | |
final String dataSource; | |
PlayerLifeCycle(this.dataSource, this.childBuilder); | |
} | |
/// A widget connecting its life cycle to a [VideoPlayerController] using | |
/// a data source from the network. | |
class NetworkPlayerLifeCycle extends PlayerLifeCycle { | |
NetworkPlayerLifeCycle(String dataSource, VideoWidgetBuilder childBuilder) | |
: super(dataSource, childBuilder); | |
@override | |
_NetworkPlayerLifeCycleState createState() => | |
new _NetworkPlayerLifeCycleState(); | |
} | |
/// A widget connecting its life cycle to a [VideoPlayerController] using | |
/// an asset as data source | |
class AssetPlayerLifeCycle extends PlayerLifeCycle { | |
AssetPlayerLifeCycle(String dataSource, VideoWidgetBuilder childBuilder) | |
: super(dataSource, childBuilder); | |
@override | |
_AssetPlayerLifeCycleState createState() => new _AssetPlayerLifeCycleState(); | |
} | |
abstract class _PlayerLifeCycleState extends State<PlayerLifeCycle> { | |
VideoPlayerController controller; | |
@override | |
/// Subclasses should implement [createVideoPlayerController], which is used | |
/// by this method. | |
void initState() { | |
super.initState(); | |
controller = createVideoPlayerController(); | |
controller.addListener(() { | |
if (controller.value.hasError) { | |
print(controller.value.errorDescription); | |
} | |
}); | |
controller.initialize(); | |
controller.setLooping(true); | |
controller.play(); | |
} | |
@override | |
void deactivate() { | |
super.deactivate(); | |
} | |
@override | |
void dispose() { | |
controller.dispose(); | |
super.dispose(); | |
} | |
@override | |
Widget build(BuildContext context) { | |
return widget.childBuilder(context, controller); | |
} | |
VideoPlayerController createVideoPlayerController(); | |
} | |
class _NetworkPlayerLifeCycleState extends _PlayerLifeCycleState { | |
@override | |
VideoPlayerController createVideoPlayerController() { | |
return new VideoPlayerController.network(widget.dataSource); | |
} | |
} | |
class _AssetPlayerLifeCycleState extends _PlayerLifeCycleState { | |
@override | |
VideoPlayerController createVideoPlayerController() { | |
return new VideoPlayerController.asset(widget.dataSource); | |
} | |
} | |
/// A filler card to show the video in a list of scrolling contents. | |
Widget buildCard(String title) { | |
return new Card( | |
child: new Column( | |
mainAxisSize: MainAxisSize.min, | |
children: <Widget>[ | |
new ListTile( | |
leading: const Icon(Icons.airline_seat_flat_angled), | |
title: new Text(title), | |
), | |
new ButtonTheme.bar( | |
child: new ButtonBar( | |
children: <Widget>[ | |
new FlatButton( | |
child: const Text('BUY TICKETS'), | |
onPressed: () {/* ... */}, | |
), | |
new FlatButton( | |
child: const Text('SELL TICKETS'), | |
onPressed: () {/* ... */}, | |
), | |
], | |
), | |
), | |
], | |
), | |
); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment