I am using the video_player package in Flutter to play videos, and when switching to fullscreen mode, I see black bars on the sides or top and bottom. I want the video to fully fill the screen without these black bars, either by stretching or adjusting the aspect ratio properly:
What I have tried:
Using BoxFit.cover – This scales the video to fill the screen but sometimes crops part of it.
Using BoxFit.fill – This stretches the video but may distort it.
Printing video and screen dimensions – The video aspect ratio sometimes doesn’t match the screen’s aspect ratio, leading to black bars.
Toggling between fit modes – Implemented a toggle to switch between BoxFit.fill and BoxFit.contain, but black bars still appear in some cases.
This is my full screen video player:
import 'package:flutter/material.dart';
import 'package:video_player/video_player.dart';
import 'package:flutter/services.dart';
class CustomVideoPlayer extends StatefulWidget {
const CustomVideoPlayer({super.key});
@override
_CustomVideoPlayerState createState() => _CustomVideoPlayerState();
}
class _CustomVideoPlayerState extends State<CustomVideoPlayer> {
late VideoPlayerController _controller;
bool isPlaying = false;
bool isStretched = false;
@override
void initState() {
super.initState();
_controller = VideoPlayerController.asset("assets/videos/sample.mp4")
..initialize().then((_) {
setState(() {});
});
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
void togglePlayPause() {
setState(() {
if (isPlaying) {
_controller.pause();
} else {
_controller.play();
}
isPlaying = !isPlaying;
});
}
void toggleStretch() {
setState(() {
isStretched = !isStretched;
});
}
void toggleFullScreen() async {
if (_controller.value.isPlaying) {
_controller.pause();
}
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => FullScreenPlayer(controller: _controller, isStretched: isStretched),
),
);
SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
]);
}
@override
Widget build(BuildContext context) {
return Column(
children: [
_controller.value.isInitialized
? SizedBox(
width: double.infinity,
height: 250,
child: FittedBox(
fit: isStretched ? BoxFit.fill : BoxFit.cover,
child: SizedBox(
width: _controller.value.size.width,
height: _controller.value.size.height,
child: VideoPlayer(_controller),
),
),
)
: const CircularProgressIndicator(),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
IconButton(
icon: Icon(isPlaying ? Icons.pause : Icons.play_arrow),
onPressed: togglePlayPause,
),
IconButton(
icon: const Icon(Icons.fullscreen),
onPressed: toggleFullScreen,
),
IconButton(
icon: Icon(isStretched ? Icons.aspect_ratio : Icons.fit_screen),
onPressed: toggleStretch,
),
],
),
],
);
}
}
class FullScreenPlayer extends StatefulWidget {
final VideoPlayerController controller;
final bool isStretched;
const FullScreenPlayer({super.key, required this.controller, required this.isStretched});
@override
_FullScreenPlayerState createState() => _FullScreenPlayerState();
}
class _FullScreenPlayerState extends State<FullScreenPlayer> {
@override
void initState() {
super.initState();
SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky);
SystemChrome.setPreferredOrientations([
DeviceOrientation.landscapeLeft,
DeviceOrientation.landscapeRight,
]);
widget.controller.addListener(() {
if (mounted) setState(() {});
});
widget.controller.play();
}
@override
void dispose() {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
]);
super.dispose();
}
@override
Widget build(BuildContext context) {
if (!widget.controller.value.isInitialized) {
return const Scaffold(
backgroundColor: Colors.black,
body: Center(
child: CircularProgressIndicator(color: Colors.white),
),
);
}
return Scaffold(
backgroundColor: Colors.black,
body: Stack(
children: [
Center(
child: FittedBox(
fit: widget.isStretched ? BoxFit.fill : BoxFit.contain,
child: SizedBox(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: VideoPlayer(widget.controller),
),
),
),
],
),
);
}
}
This is my homepage:
import 'package:flutter/material.dart';
import 'package:livestream_project/pages/video_player/player_code.dart'; // Update the path
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: const Center(
child: CustomVideoPlayer(),
),
);
}
}
This is my AndroidManifest.xml:
<manifest xmlns:android=";>
<application
android:label="livestream_project"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:taskAffinity=""
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
android:name="flutterEmbedding"
android:value="2" />
</application>
<!-- Required to query activities that can process text, see:
and
.
In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
<queries>
<intent>
<action android:name="android.intent.action.PROCESS_TEXT"/>
<data android:mimeType="text/plain"/>
</intent>
</queries>
</manifest>
This is my main.dart:
import 'package:flutter/material.dart';
import 'pages/homepage_page.dart'; // Import the HomePage
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Live Stream Player',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const HomePage(), // Set HomePage as the home screen
);
}
}
I am using the video_player package in Flutter to play videos, and when switching to fullscreen mode, I see black bars on the sides or top and bottom. I want the video to fully fill the screen without these black bars, either by stretching or adjusting the aspect ratio properly:
What I have tried:
Using BoxFit.cover – This scales the video to fill the screen but sometimes crops part of it.
Using BoxFit.fill – This stretches the video but may distort it.
Printing video and screen dimensions – The video aspect ratio sometimes doesn’t match the screen’s aspect ratio, leading to black bars.
Toggling between fit modes – Implemented a toggle to switch between BoxFit.fill and BoxFit.contain, but black bars still appear in some cases.
This is my full screen video player:
import 'package:flutter/material.dart';
import 'package:video_player/video_player.dart';
import 'package:flutter/services.dart';
class CustomVideoPlayer extends StatefulWidget {
const CustomVideoPlayer({super.key});
@override
_CustomVideoPlayerState createState() => _CustomVideoPlayerState();
}
class _CustomVideoPlayerState extends State<CustomVideoPlayer> {
late VideoPlayerController _controller;
bool isPlaying = false;
bool isStretched = false;
@override
void initState() {
super.initState();
_controller = VideoPlayerController.asset("assets/videos/sample.mp4")
..initialize().then((_) {
setState(() {});
});
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
void togglePlayPause() {
setState(() {
if (isPlaying) {
_controller.pause();
} else {
_controller.play();
}
isPlaying = !isPlaying;
});
}
void toggleStretch() {
setState(() {
isStretched = !isStretched;
});
}
void toggleFullScreen() async {
if (_controller.value.isPlaying) {
_controller.pause();
}
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => FullScreenPlayer(controller: _controller, isStretched: isStretched),
),
);
SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
]);
}
@override
Widget build(BuildContext context) {
return Column(
children: [
_controller.value.isInitialized
? SizedBox(
width: double.infinity,
height: 250,
child: FittedBox(
fit: isStretched ? BoxFit.fill : BoxFit.cover,
child: SizedBox(
width: _controller.value.size.width,
height: _controller.value.size.height,
child: VideoPlayer(_controller),
),
),
)
: const CircularProgressIndicator(),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
IconButton(
icon: Icon(isPlaying ? Icons.pause : Icons.play_arrow),
onPressed: togglePlayPause,
),
IconButton(
icon: const Icon(Icons.fullscreen),
onPressed: toggleFullScreen,
),
IconButton(
icon: Icon(isStretched ? Icons.aspect_ratio : Icons.fit_screen),
onPressed: toggleStretch,
),
],
),
],
);
}
}
class FullScreenPlayer extends StatefulWidget {
final VideoPlayerController controller;
final bool isStretched;
const FullScreenPlayer({super.key, required this.controller, required this.isStretched});
@override
_FullScreenPlayerState createState() => _FullScreenPlayerState();
}
class _FullScreenPlayerState extends State<FullScreenPlayer> {
@override
void initState() {
super.initState();
SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky);
SystemChrome.setPreferredOrientations([
DeviceOrientation.landscapeLeft,
DeviceOrientation.landscapeRight,
]);
widget.controller.addListener(() {
if (mounted) setState(() {});
});
widget.controller.play();
}
@override
void dispose() {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
]);
super.dispose();
}
@override
Widget build(BuildContext context) {
if (!widget.controller.value.isInitialized) {
return const Scaffold(
backgroundColor: Colors.black,
body: Center(
child: CircularProgressIndicator(color: Colors.white),
),
);
}
return Scaffold(
backgroundColor: Colors.black,
body: Stack(
children: [
Center(
child: FittedBox(
fit: widget.isStretched ? BoxFit.fill : BoxFit.contain,
child: SizedBox(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: VideoPlayer(widget.controller),
),
),
),
],
),
);
}
}
This is my homepage:
import 'package:flutter/material.dart';
import 'package:livestream_project/pages/video_player/player_code.dart'; // Update the path
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: const Center(
child: CustomVideoPlayer(),
),
);
}
}
This is my AndroidManifest.xml:
<manifest xmlns:android="http://schemas.android/apk/res/android">
<application
android:label="livestream_project"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:taskAffinity=""
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
android:name="flutterEmbedding"
android:value="2" />
</application>
<!-- Required to query activities that can process text, see:
https://developer.android/training/package-visibility and
https://developer.android/reference/android/content/Intent#ACTION_PROCESS_TEXT.
In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
<queries>
<intent>
<action android:name="android.intent.action.PROCESS_TEXT"/>
<data android:mimeType="text/plain"/>
</intent>
</queries>
</manifest>
This is my main.dart:
import 'package:flutter/material.dart';
import 'pages/homepage_page.dart'; // Import the HomePage
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Live Stream Player',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const HomePage(), // Set HomePage as the home screen
);
}
}
Share
Improve this question
edited Mar 22 at 8:33
tyg
16.6k4 gold badges37 silver badges49 bronze badges
asked Mar 22 at 7:18
shubham goyalshubham goyal
1
2
- What do you mean by "How to remove black bars when using the front camera?" It seems that the front camera has no relationship with your issue. – DevQt Commented Mar 22 at 9:39
- Please clarify your specific problem or provide additional details to highlight exactly what you need. As it's currently written, it's hard to tell exactly what you're asking. – DevQt Commented Mar 22 at 9:39
1 Answer
Reset to default 0I think it will depend on the aspect ratio of the original video.
You can't dodge the black bars without cropping in my opinion, for example if you have a 4:3 content displayed on a 16:9 screen, you will have black bars
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744322988a4568512.html
评论列表(0条)