I am new to the world of Flutter, I am creating a video player with the following libraries:
-Video_Player
-chewie
The problem is that I follow the instructions in the documentation and also in several videos on YouTube, only that the video plays in the background (audio is heard), but the video does not appear. For more information about my problem, I attach my code, I thank you in advance for all the help provided.
import 'package:flutter/material.dart';
import 'package:chewie/chewie.dart';
import 'package:video_player/video_player.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return const MaterialApp(
title: 'Euforia',
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
#override
// ignore: library_private_types_in_public_api
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
late VideoPlayerController controller;
ChewieController? chewieController;
Future<void> loadVideoPlayer() async {
controller = VideoPlayerController.network(
"https://download1486.mediafire.com/xtpol73k5d0g/6udcu6b0onjnuv5/Santa+RM+-+Mucho+Para+M%C3%AD+%28Ft.+Franco+Escamilla%29+%5BVideo+Oficial%5D_2.mp4");
await Future.wait([controller.initialize()]);
chewieController = ChewieController(
videoPlayerController: controller, autoPlay: true, looping: false);
}
#override
void initState() {
super.initState();
loadVideoPlayer();
}
#override
void dispose() {
super.dispose();
controller.dispose();
chewieController!.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Hola Mundo')),
body: Column(
children: [
Expanded(
child: Center(
child: chewieController != null &&
chewieController!.videoPlayerController.value.isInitialized
? Chewie(controller: chewieController!)
: Center(
child: Column(
children: const [
CircularProgressIndicator(),
SizedBox(
height: 60.0,
),
Text("Cargando")
],
),
),
))
],
),
);
}
}
I also provide the official page
https://pub.dev/packages/chewie
After initializing controller and video you need to update screen state. Try this in Init Code:
#override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
await loadVideoPlayer();
setState(() {});
});
}
Related
I'm working on a Flutterflow project and when I attempt to compile my widget inside of the custom widget section it returns multiple errors. Here is the code directly from pub.dev and I am adding the dependencies in the right section but I am continually getting the same errors.
import 'package:video_player/video_player.dart';
void main() => runApp(const VideoApp());
/// Stateful widget to fetch and then display video content.
class VideoApp extends StatefulWidget {
const VideoApp({Key? key}) : super(key: key);
#override
_VideoAppState createState() => _VideoAppState();
}
class _VideoAppState extends State<VideoApp> {
late VideoPlayerController _controller;
#override
void initState() {
super.initState();
_controller = VideoPlayerController.network(
'https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4')
..initialize().then((_) {
// Ensure the first frame is shown after the video is initialized, even before the play button has been pressed.
setState(() {});
});
}
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Video Demo',
home: Scaffold(
body: Center(
child: _controller.value.isInitialized
? AspectRatio(
aspectRatio: _controller.value.aspectRatio,
child: VideoPlayer(_controller),
)
: Container(),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
setState(() {
_controller.value.isPlaying
? _controller.pause()
: _controller.play();
});
},
child: Icon(
_controller.value.isPlaying ? Icons.pause : Icons.play_arrow,
),
),
),
);
}
#override
void dispose() {
super.dispose();
_controller.dispose();
}
}
LateInitializationError: Field '_latestValue#875205881' has not been initialized
Error image
I do not know what is the cause of the problem I tried to put ? Instead of late but there are still mistakes
Help me, thanks
video_screen.dart
import 'package:flutter/material.dart';
import '../screens/chewie_list_item.dart';
import 'package:chewie/chewie.dart';
import 'package:video_player/video_player.dart';
class VideoScreen extends StatefulWidget {
const VideoScreen({Key? key}) : super(key: key);
#override
_VideoScreenState createState() => _VideoScreenState();
}
class _VideoScreenState extends State<VideoScreen> {
ChewieController? _chewieController;
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView(
children: <Widget>[
ChewieListItem(
videoPlayerController: VideoPlayerController.asset(
'videos/video1.mp4',
),
looping: true,
),
ChewieListItem(
videoPlayerController: VideoPlayerController.asset(
'videos/video2.mp4',
),
looping: true,
),
],
),
);
}
}
chewie_list_item.dart
import 'package:chewie/chewie.dart';
import 'package:flutter/material.dart';
import 'package:video_player/video_player.dart';
class ChewieListItem extends StatefulWidget {
// This will contain the URL/asset path which we want to play
final VideoPlayerController videoPlayerController;
final bool looping;
ChewieListItem({
required this.videoPlayerController,
required this.looping,
Key? key,
}) : super(key: key);
#override
_ChewieListItemState createState() => _ChewieListItemState();
}
class _ChewieListItemState extends State<ChewieListItem> {
late ChewieController _chewieController;
#override
void initState() {
super.initState();
// Wrapper on top of the videoPlayerController
_chewieController = ChewieController(
videoPlayerController: widget.videoPlayerController,
aspectRatio: 16 / 9,
// Prepare the video to be played and display the first frame
autoInitialize: true,
looping: widget.looping,
// Errors can occur for example when trying to play a video
// from a non-existent URL
errorBuilder: (context, errorMessage) {
return Center(
child: Text(
errorMessage,
style: TextStyle(color: Colors.white),
),
);
},
);
}
#override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.all(8.0),
child: Chewie(
controller: _chewieController,
),
);
}
#override
void dispose() {
super.dispose();
// IMPORTANT to dispose of all the used resources
widget.videoPlayerController.dispose();
_chewieController.dispose();
}
}
I am getting videoplayer overflow. How do I resize my video player, so it correctly works. Error message "A RenderFlex overflowed by 93 pixels on the right" during window resizing.
import 'package:flutter/material.dart';
import 'package:video_player/video_player.dart';
import 'package:provider/provider.dart';
class VolumeManager with ChangeNotifier{
var _volume=50.0;
double get volume=>_volume;
void setVolume({
required double volumeValue,
required VideoPlayerController controller
}){
_volume=volumeValue;
controller.setVolume(_volume);
notifyListeners();
}
}
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Test Video',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home:
ChangeNotifierProvider(create:(context)=>VolumeManager(),child: Test_LoadVideoWidget()),
);
}
}
class Test_LoadVideoWidget extends StatefulWidget {
Test_LoadVideoWidget({Key? key}) : super(key: key);
#override
State<Test_LoadVideoWidget> createState() => _Test_LoadVideoWidgetState();
}
class _Test_LoadVideoWidgetState extends State<Test_LoadVideoWidget> {
late final VideoPlayerController controller;
late final Future<void>initVideo;
#override
void initState() {
// TODO: implement initState
super.initState();
controller=VideoPlayerController.asset("assets/video/butterfly.mp4");
controller.setLooping(true);
initVideo=controller.initialize();
}
#override
void dispose() {
// TODO: implement dispose
controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return FutureBuilder<void>(
future:initVideo,
builder:(context,snapshot){
if (snapshot.connectionState==ConnectionState.done){
return Test_VideoWidget(controller);
}
return Center(child:CircularProgressIndicator());
}
);
}
}
class Test_VideoWidget extends StatelessWidget {
final VideoPlayerController controller;
Test_VideoWidget(this.controller);
void _play(){
if (!controller.value.isPlaying){
controller.play();
}
}
void _pause(){
if (controller.value.isPlaying){
controller.pause();
}
}
#override
Widget build(BuildContext context) {
return Scaffold(appBar: AppBar(title:Text("Test Video",style:Theme.of(context).textTheme.headline2)),
body:
Container(
width:MediaQuery.of(context).size.width,
//height:MediaQuery.of(context).size.height,
padding:EdgeInsets.all(20),child:
Column(
mainAxisAlignment:MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
AspectRatio(aspectRatio: controller.value.aspectRatio,
child:VideoPlayer(controller),
),
Row(children: [
SizedBox(width:200,child:ElevatedButton(onPressed: (){_play();}, child: Text("Play!",style:Theme.of(context).textTheme.button))),
const SizedBox(height:50,width:200),
SizedBox(width:200,child:ElevatedButton(onPressed:(){_pause();}, child:Text("Pause",style:Theme.of(context).textTheme.button))),
],)
,Consumer<VolumeManager>(
builder:(context,manager,_)
=>Slider(
min: 0,
max: 100,
value: manager.volume,
onChanged: (value) =>
{
manager.setVolume(volumeValue: value, controller: controller)
}
),
)
],)
)
);
}
}
solution: I used SingleChildScrollView to solve the horizontal and vertical renderflex overflow errors. I changed the Consumer to use => notation rather than { return notation.
import 'package:flutter/material.dart';
import 'package:video_player/video_player.dart';
import 'package:provider/provider.dart';
class VolumeManager with ChangeNotifier{
var _volume=50.0;
double get volume=>_volume;
void setVolume({
required double volumeValue,
required VideoPlayerController controller
}){
_volume=volumeValue;
controller.setVolume(_volume);
notifyListeners();
}
}
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Test Video',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home:
ChangeNotifierProvider(create:(context)=>VolumeManager(),child: Test_LoadVideoWidget()),
);
}
}
class Test_LoadVideoWidget extends StatefulWidget {
Test_LoadVideoWidget({Key? key}) : super(key: key);
#override
State<Test_LoadVideoWidget> createState() => _Test_LoadVideoWidgetState();
}
class _Test_LoadVideoWidgetState extends State<Test_LoadVideoWidget> {
late final VideoPlayerController controller;
late final Future<void>initVideo;
#override
void initState() {
// TODO: implement initState
super.initState();
controller=VideoPlayerController.asset("assets/video/butterfly.mp4");
//..initialize().then((_){
//controller.play();
//controller.setLooping(true);
setState(() {
});
//});
initVideo = controller.initialize();
}
#override
void dispose() {
// TODO: implement dispose
controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
//return Test_VideoWidget(controller);
return FutureBuilder<void>(
future:initVideo,
builder:(context,snapshot){
if (snapshot.connectionState==ConnectionState.done){
return Test_VideoWidget(controller);
}
return Center(child:CircularProgressIndicator());
}
);
}
}
class Test_VideoWidget extends StatelessWidget {
final VideoPlayerController controller;
Test_VideoWidget(this.controller);
void _play(){
if (!controller.value.isPlaying){
controller.play();
}
}
void _pause(){
if (controller.value.isPlaying){
controller.pause();
}
}
#override
Widget build(BuildContext context) {
return Scaffold(appBar: AppBar(title:Text("Test Video",style:Theme.of(context).textTheme.headline2)),
body:
// controller.value.isInitialized?
Container(
width:MediaQuery.of(context).size.width,
height:MediaQuery.of(context).size.height,
padding:EdgeInsets.all(20),child:
SingleChildScrollView(child:Column(
mainAxisAlignment:MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
AspectRatio(aspectRatio: controller.value.aspectRatio,
child:VideoPlayer(controller),
),
SingleChildScrollView(scrollDirection: Axis.horizontal, child: Row(children: [
SizedBox(width:200,child:ElevatedButton(onPressed: (){_play();}, child: Text("Play!",style:Theme.of(context).textTheme.button))),
const SizedBox(height:50,width:200),
SizedBox(width:200,child:ElevatedButton(onPressed:(){_pause();}, child:Text("Pause",style:Theme.of(context).textTheme.button))),
],))
,Consumer<VolumeManager>(
builder:(context,manager,_)=>
Slider(
min: 0,
max: 50,
value: manager.volume,
onChanged: (value) =>
{
manager.setVolume(volumeValue: value, controller: controller)
}
),
)
],)
)
//:
// Center(child:CircularProgressIndicator()),
));
}
}
I am new to flutter and am kinda lost on how to set up a time to my splash screen so after this time it goes to the main screen. am using rive for the splash screen
import 'package:flutter/material.dart';
import 'package:rive/rive.dart';
void main() {
runApp(const MaterialApp(home: SimpleAnimation()));
}
class SimpleAnimation extends StatelessWidget {
const SimpleAnimation({Key? key, this.loading}) : super(key: key);
final bool? loading;
#override
Widget build(BuildContext context) {
return const Scaffold(
body: Center(
child: RiveAnimation.asset('assets/splash/splash.riv',
fit: BoxFit.cover)
),
);
}
}
You can set 3 second time in initstate after navigate to which screen you want
class SplashScreen extends StatefulWidget {
const SplashScreen({Key? key}) : super(key: key);
#override
_SplashScreenState createState() => _SplashScreenState();
}
class _SplashScreenState extends State<SplashScreen> {
#override
void initState() {
// TODO: implement initState
super.initState();
// after 3 second it will navigate
Future.delayed(const Duration(seconds: 3)).then((val) {
// Navigation Here
});
}
#override
Widget build(BuildContext context) {
return const Scaffold(
// your code
);
}
}
#override
void initState() {
//set timer for splash screen
Timer(const Duration(seconds: 4), () async {
//add your logic here
Navigator.pushNamedAndRemoveUntil(
context, ScreenRoute.mainScreen, (route) => false);
super.initState();
}
This SimpleAnimation widget shows after the splash screen. While this is StatelessWidget widget, you can define method inside build method. Change Duration(seconds: 2) based on your need.
class SimpleAnimation extends StatelessWidget {
const SimpleAnimation({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
Future.delayed(const Duration(seconds: 2)).then((value) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const NextScreen(),
));
});
return const Scaffold(
body: Center(
As folks already mentioned the straighforward way would be to add a delay and do navigation after it:
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return const MaterialApp(
title: 'Flutter Demo',
home: SplashScreen(),
);
}
}
class SplashScreen extends StatefulWidget {
const SplashScreen({Key? key}) : super(key: key);
#override
State<SplashScreen> createState() => _SplashScreenState();
}
class _SplashScreenState extends State<SplashScreen> {
#override
void initState() {
super.initState();
Future.delayed(const Duration(seconds: 2), () {
if (mounted) {
Navigator.of(context).pushReplacement(
MaterialPageRoute(
builder: (context) => const MainScreen(),
),
);
}
});
}
#override
Widget build(BuildContext context) {
return const ColoredBox(color: Colors.green);
}
}
class MainScreen extends StatelessWidget {
const MainScreen({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return const ColoredBox(color: Colors.yellow);
}
}
Though, with this implementation, you'll have to depend on the animation length. So when you'll update animation - you'll have not to forget to update it inside the splash screen. A more reliable (and complex) solution would be to listen to the animation status and do the navigation after the animation finishes. Like this (warning, change ):
class PlayOneShotAnimation extends StatefulWidget {
const PlayOneShotAnimation({Key? key}) : super(key: key);
#override
_PlayOneShotAnimationState createState() => _PlayOneShotAnimationState();
}
class _PlayOneShotAnimationState extends State<PlayOneShotAnimation> {
late RiveAnimationController _controller;
#override
void initState() {
super.initState();
_controller = OneShotAnimation(
'bounce',
autoplay: true,
onStop: () {
Navigator.of(context).push(
MaterialPageRoute<void>(
builder: (context) => const MainScreen(),
),
);
},
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: RiveAnimation.network(
'https://cdn.rive.app/animations/vehicles.riv',
animations: const ['idle', 'curves'],
controllers: [_controller],
),
),
);
}
}
class MainScreen extends StatelessWidget {
const MainScreen({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return const ColoredBox(color: Colors.yellow);
}
}
This is my approach for splash screen, the advantage of this approach is to make sure that the splash screen launch only once when the app starting.
First define a static bool in app home class to indicate the app launch.
static bool launch = true;
Then at the home attribute in your MaterialApp widget at app home class, check if (launch) is true use a FutureBuilder to launch the splash screen, if (launch) is false set home to your second screen. With FutureBuilder you can set a timer for your splash screen, when it done your second screen will start (credit to https://stackoverflow.com/a/68699447/11619215).
home: launch? FutureBuilder(
future: Future.delayed(const Duration(seconds: 3)),
builder: (ctx, timer) =>
timer.connectionState == ConnectionState.done
? const SecondScreen(title: 'Flutter Demo Home Page')
: appSplashScreen(),
): const SecondScreen(title: 'Flutter Demo Home Page'),
In the Second screen, check if (launch) is true then set it to false. This will make sure that the splash screen will only launch once each time your application start.
if(AppHome.launch) {
AppHome.launch = false;
}
Below is the full code with appSplashScreen widget at the bottom:
import 'package:flutter/material.dart';
void main() {
runApp(const AppHome());
}
class AppHome extends StatelessWidget {
const AppHome({Key? key}) : super(key: key);
//static bool to indicate the launching of the app
static bool launch = true;
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: launch? FutureBuilder(
future: Future.delayed(const Duration(seconds: 3)),
builder: (ctx, timer) =>
timer.connectionState == ConnectionState.done
? const SecondScreen(title: 'Flutter Demo Home Page')
: appSplashScreen(),
): const SecondScreen(title: 'Flutter Demo Home Page'),
);
}
}
class SecondScreen extends StatefulWidget {
const SecondScreen({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<SecondScreen> createState() => _SecondScreenState();
}
class _SecondScreenState extends State<SecondScreen> {
#override
Widget build(BuildContext context) {
//mack sure your splash screen only launch once at your app starting
if(AppHome.launch) {
AppHome.launch = false;
}
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: const Center(
child: Text(
'My Second screen',
),
),
);
}
}
Widget appSplashScreen() {
return Container(
decoration: const BoxDecoration(
////you can add background image/color to your splash screen
// image: DecorationImage(
// image: AssetImage('assets/background.png'),
// fit: BoxFit.cover,
// ),
color: Colors.white,
),
child: Center(
child: SizedBox(
//get MediaQuery from instance of window to get height and width (no need of context)
height: MediaQueryData.fromWindow(WidgetsBinding.instance.window).size.height*0.5,
width: MediaQueryData.fromWindow(WidgetsBinding.instance.window).size.width*0.5,
child: Column(
children: const [
////you can add image to your splash screen
// Image(
// image: AssetImage('assets/splashscreen_image.png'),
// ),
FittedBox(
child: Text(
'Loading',
textAlign: TextAlign.center,
style: TextStyle(
decoration: TextDecoration.none,
),
)
),
CircularProgressIndicator(),
],
),
),
),
);
}
I am trying to put a full camera in a container that is 255 in height and full in width.
I've tried a lot of tweaking the code below, but I'm not sure how to apply the ratio.
in widget size
Is there no room to fix it with the correct camera aspect ratio?
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:camera/camera.dart';
List<CameraDescription> cameras;
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
cameras = await availableCameras();
runApp(CameraApp());
}
class CameraApp extends StatefulWidget {
#override
_CameraAppState createState() => _CameraAppState();
}
class _CameraAppState extends State<CameraApp> {
CameraController controller;
#override
void initState() {
super.initState();
controller = CameraController(cameras[0], ResolutionPreset.max);
controller.initialize().then((_) {
if (!mounted) {
return;
}
setState(() {});
});
}
#override
void dispose() {
controller?.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
if (!controller.value.isInitialized) {
return Container();
}
return MaterialApp(
home: CameraPreview(controller),
);
}
}
The CameraPreview class cannot be modified according to your height and width. If you try to put the CameraPreview inside a sizedbox OR AspectRatio class, then it will give you a skewed image. The best option to get a preview without skewing the output is to use a stack. Sample code is below:
import 'package:flutter/material.dart';
import 'package:camera/camera.dart';
List<CameraDescription> cameras = List.empty(growable: true);
void main() async {
WidgetsFlutterBinding.ensureInitialized();
cameras = await availableCameras();
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return const MaterialApp(
title: 'My Flutter Camera',
home: CameraApp(),
);
}
}
class CameraApp extends StatefulWidget {
const CameraApp({Key? key}) : super(key: key);
#override
_CameraAppState createState() => _CameraAppState();
}
class _CameraAppState extends State<CameraApp> {
CameraController controller =
CameraController(cameras[1], ResolutionPreset.max);
#override
void initState() {
super.initState();
controller.initialize().then((_) {
if (!mounted) {
return;
}
setState(() {});
});
}
#override
void dispose() {
controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
if (!controller.value.isInitialized) {
return Container();
}
return Stack(
children: [
CameraPreview(controller),
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
color: Colors.white,
height: (MediaQuery.of(this.context).size.height - 255) / 2,
),
const SizedBox(
height: 255,
),
Container(
color: Colors.white,
height: (MediaQuery.of(this.context).size.height - 255) / 2,
),
],
)
],
);
}
}