Created
January 16, 2023 11:29
-
-
Save Sp4Rx/3b9e1d8988144c8a6e3449a53acfb38a to your computer and use it in GitHub Desktop.
Video in page view
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'; | |
///Set your video from asset. | |
const String VIDEO_ASSET = 'assets/Butterfly-209.mp4'; | |
void main() { | |
runApp( | |
MaterialApp( | |
home: _App(), | |
), | |
); | |
} | |
class _App extends StatelessWidget { | |
@override | |
Widget build(BuildContext context) { | |
return _ButterFlyAssetVideoInList(); | |
} | |
} | |
class _ButterFlyAssetVideoInList extends StatelessWidget { | |
@override | |
Widget build(BuildContext context) { | |
return Scaffold( | |
body: PageView( | |
children: <Widget>[ | |
_ButterFlyAssetVideo(), | |
_ButterFlyAssetVideo(), | |
_ButterFlyAssetVideo(), | |
], | |
), | |
); | |
} | |
} | |
class _ButterFlyAssetVideo extends StatefulWidget { | |
@override | |
_ButterFlyAssetVideoState createState() => _ButterFlyAssetVideoState(); | |
} | |
class _ButterFlyAssetVideoState extends State<_ButterFlyAssetVideo> { | |
late VideoPlayerController _controller; | |
@override | |
void initState() { | |
super.initState(); | |
_controller = VideoPlayerController.asset(VIDEO_ASSET); | |
_controller.addListener(() { | |
setState(() {}); | |
}); | |
_controller.setLooping(true); | |
_controller.initialize().then((_) => setState(() {})); | |
_controller.play(); | |
} | |
@override | |
void dispose() { | |
_controller.dispose(); | |
super.dispose(); | |
} | |
@override | |
Widget build(BuildContext context) { | |
return SingleChildScrollView( | |
child: Column( | |
children: <Widget>[ | |
Container( | |
padding: const EdgeInsets.only(top: 20.0), | |
), | |
const Text('With assets mp4'), | |
Container( | |
padding: const EdgeInsets.all(20), | |
child: AspectRatio( | |
aspectRatio: _controller.value.aspectRatio, | |
child: Stack( | |
alignment: Alignment.bottomCenter, | |
children: <Widget>[ | |
VideoPlayer(_controller), | |
_ControlsOverlay(controller: _controller), | |
VideoProgressIndicator(_controller, allowScrubbing: true), | |
], | |
), | |
), | |
), | |
], | |
), | |
); | |
} | |
} | |
class _ControlsOverlay extends StatelessWidget { | |
const _ControlsOverlay({Key? key, required this.controller}) | |
: super(key: key); | |
static const List<Duration> _exampleCaptionOffsets = <Duration>[ | |
Duration(seconds: -10), | |
Duration(seconds: -3), | |
Duration(seconds: -1, milliseconds: -500), | |
Duration(milliseconds: -250), | |
Duration.zero, | |
Duration(milliseconds: 250), | |
Duration(seconds: 1, milliseconds: 500), | |
Duration(seconds: 3), | |
Duration(seconds: 10), | |
]; | |
static const List<double> _examplePlaybackRates = <double>[ | |
0.25, | |
0.5, | |
1.0, | |
1.5, | |
2.0, | |
3.0, | |
5.0, | |
10.0, | |
]; | |
final VideoPlayerController controller; | |
@override | |
Widget build(BuildContext context) { | |
return Stack( | |
children: <Widget>[ | |
AnimatedSwitcher( | |
duration: const Duration(milliseconds: 50), | |
reverseDuration: const Duration(milliseconds: 200), | |
child: controller.value.isPlaying | |
? const SizedBox.shrink() | |
: Container( | |
color: Colors.black26, | |
child: const Center( | |
child: Icon( | |
Icons.play_arrow, | |
color: Colors.white, | |
size: 100.0, | |
semanticLabel: 'Play', | |
), | |
), | |
), | |
), | |
GestureDetector( | |
onTap: () { | |
controller.value.isPlaying ? controller.pause() : controller.play(); | |
}, | |
), | |
Align( | |
alignment: Alignment.topLeft, | |
child: PopupMenuButton<Duration>( | |
initialValue: controller.value.captionOffset, | |
tooltip: 'Caption Offset', | |
onSelected: (Duration delay) { | |
controller.setCaptionOffset(delay); | |
}, | |
itemBuilder: (BuildContext context) { | |
return <PopupMenuItem<Duration>>[ | |
for (final Duration offsetDuration in _exampleCaptionOffsets) | |
PopupMenuItem<Duration>( | |
value: offsetDuration, | |
child: Text('${offsetDuration.inMilliseconds}ms'), | |
) | |
]; | |
}, | |
child: Padding( | |
padding: const EdgeInsets.symmetric( | |
// Using less vertical padding as the text is also longer | |
// horizontally, so it feels like it would need more spacing | |
// horizontally (matching the aspect ratio of the video). | |
vertical: 12, | |
horizontal: 16, | |
), | |
child: Text('${controller.value.captionOffset.inMilliseconds}ms'), | |
), | |
), | |
), | |
Align( | |
alignment: Alignment.topRight, | |
child: PopupMenuButton<double>( | |
initialValue: controller.value.playbackSpeed, | |
tooltip: 'Playback speed', | |
onSelected: (double speed) { | |
controller.setPlaybackSpeed(speed); | |
}, | |
itemBuilder: (BuildContext context) { | |
return <PopupMenuItem<double>>[ | |
for (final double speed in _examplePlaybackRates) | |
PopupMenuItem<double>( | |
value: speed, | |
child: Text('${speed}x'), | |
) | |
]; | |
}, | |
child: Padding( | |
padding: const EdgeInsets.symmetric( | |
// Using less vertical padding as the text is also longer | |
// horizontally, so it feels like it would need more spacing | |
// horizontally (matching the aspect ratio of the video). | |
vertical: 12, | |
horizontal: 16, | |
), | |
child: Text('${controller.value.playbackSpeed}x'), | |
), | |
), | |
), | |
], | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment