这是一个按顺序播放视频的小部件。它缓存上一个和下一个视频,以实现流畅的用户体验。它将侦听器附加到,
VideoPlayerController以获取视频的当前位置。当前视频结束时,它也会跳过下一个视频。
class MyHomePage extends StatefulWidget { MyHomePage({Key key}) : super(key: key); @override _MyHomePageState createState() => _MyHomePageState();}class _MyHomePageState extends State<MyHomePage> { int index = 0; double _progress = 0; bool _changeLock = false; List<VideoPlayerController> _controllers = []; List<String> _urls = [ 'https://flutter.github.io/assets-for-api-docs/assets/videos/butterfly.mp4#1', 'https://flutter.github.io/assets-for-api-docs/assets/videos/butterfly.mp4#1', 'https://flutter.github.io/assets-for-api-docs/assets/videos/butterfly.mp4#1', 'https://flutter.github.io/assets-for-api-docs/assets/videos/butterfly.mp4#1', 'https://flutter.github.io/assets-for-api-docs/assets/videos/butterfly.mp4#1', ]; @override void initState() { super.initState(); _initControllers(); } _initControllers() { _controllers.add(null); for (int i = 0; i < _urls.length; i++) { if (i == 2) { break; } _controllers.add(VideoPlayerController.network(_urls[i])); } attachListenerAndInit(_controllers[1]).then((_) { _controllers[1].play().then((_) { setState(() {}); }); }); if (_controllers.length > 2) { attachListenerAndInit(_controllers[2]); } } Future<void> attachListenerAndInit(VideoPlayerController controller) async { if (!controller.hasListeners) { controller.addListener(() { int dur = controller.value.duration.inMilliseconds; int pos = controller.value.position.inMilliseconds; setState(() { if (dur <= pos) { _progress = 0; } else { _progress = (dur - (dur - pos)) / dur; } }); if (dur - pos < 1) { controller.seekTo(Duration(milliseconds: 0)); nextVideo(); } }); } await controller.initialize().then((_) {}); return; } void previousVideo() { if (_changeLock) { return; } _changeLock = true; if (index == 0) { _changeLock = false; return; } _controllers[1]?.pause(); index--; if (index != _urls.length - 2) { _controllers.last?.dispose(); _controllers.removeLast(); } if (index != 0) { _controllers.insert(0, VideoPlayerController.network(_urls[index - 1])); attachListenerAndInit(_controllers.first); } else { _controllers.insert(0, null); } _controllers[1].play().then((_) { setState(() { _changeLock = false; }); }); } void nextVideo() { if (_changeLock) { return; } _changeLock = true; if (index == _urls.length - 1) { _changeLock = false; return; } _controllers[1]?.pause(); index++; _controllers.first?.dispose(); _controllers.removeAt(0); if (index != _urls.length - 1) { _controllers.add(VideoPlayerController.network(_urls[index + 1])); attachListenerAndInit(_controllers.last); } _controllers[1].play().then((_) { setState(() { _changeLock = false; }); }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("${index + 1} of ${_urls.length}"), ), body: Stack( children: <Widget>[ SizedBox( height: MediaQuery.of(context).size.height, width: MediaQuery.of(context).size.width, child: Center(child: VideoPlayer(_controllers[1]))), Positioned( child: Container( height: 10, width: MediaQuery.of(context).size.width * _progress, color: Colors.white, ), ) ], ), floatingActionButton: Row( mainAxisAlignment: MainAxisAlignment.end, children: <Widget>[ FloatingActionButton( onPressed: previousVideo, child: Icon(Icons.arrow_back), ), SizedBox( width: 24, ), FloatingActionButton( onPressed: nextVideo, child: Icon(Icons.arrow_forward), ) ], ), ); }}我编写的缓存算法使用的a
List具有3个值。
VideoPlayer使用中间(第二)值。第一个和第三个值用于缓存。此列表上有三种可能性。
当我们在第一个网址上时:
null VideoPlayerController <- Currently playingVideoPlayerController <- Cached for next
当我们在最后一个URL上时:
VideoPlayerController <- Cached for previousVideoPlayerController <- Currently playingnull
其余条件:
VideoPlayerController <- Cached for previousVideoPlayerController <- Currently playingVideoPlayerController <- Cached for next



