Interactive Video Grid In Flutter
![Interactive Video Grid In Flutter](https://i0.wp.com/flutterexperts.com/wp-content/uploads/2025/02/Interactive-Video-Grid-In-Flutter.jpg?fit=2160%2C1244&ssl=1)
Flutter has arisen as an incredible tool for building outwardly rich and responsive applications. One of its numerous capacities is making intelligent media-rich parts like a video grid.
In this article, we will explore the Interactive Video Grid In Flutter. We will execute a demo program and show to user-interactive video grid utilizing the video_player and flutter_bloc package in your Flutter applications.
If you’re looking for the best Flutter app development company for your mobile application then feel free to contact us at — support@flutterdevs.com.
For Video Player :
video_player | Flutter package
Flutter plugin for displaying inline video with other Flutter widgets on Android, iOS, and web.pub.dev
For Flutter Bloc:
Table Of Contents::
![](https://i0.wp.com/flutterexperts.com/wp-content/uploads/2025/02/giphy-2.gif?resize=480%2C270&ssl=1)
Introduction:
An interactive video grid is a collection of videos organized in a grid layout where users can connect with individual video things. This powerful cooperation guarantees that the connection point is natural and drawing in, particularly for applications like media libraries, video tutorial exercises, or e-commerce platform stages exhibiting item demos.
This demo video shows how to create an interactive video grid in Flutter and how an interactive video grid will work using the video_player and flutter_bloc packages in your Flutter applications. We will show a user that tapping or hovering over a video starts its playback, while others pause. It will be shown on your device.
Demo Module::
![](https://i0.wp.com/flutterexperts.com/wp-content/uploads/2025/02/1000128501.gif?resize=400%2C867&ssl=1)
Features:
- Videos are shown in a flawless grid format.
- Users can play a video by tapping or drifting on it.
- At the point when a video is done, a placeholder picture is shown.
- Just a single video plays all at once to save assets and keep up with clarity.
Implementation:
Step 1: Add the dependencies
Add dependencies to pubspec — yaml file.
dependencies:
flutter:
sdk: flutter
video_player: ^2.9.2
flutter_bloc: ^9.0.0
Step 2: Import
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:video_player/video_player.dart';
Step 3: Run flutter packages get in the root directory of your app.
Code Implement:
You need to implement it in your code respectively:
Create a new dart file called video_
item_model.dart
inside the lib
folder.
First, we need a model to represent each video item model. In this class, we will add three final strings url, title, and description,
class VideoItemModel {
final String url;
final String title;
final String description;
VideoItemModel({required this.url, required this.title, required this.description});
}
Create a new dart file called video_
cubit.dart
inside the lib
folder.
In this file, we will oversee the state with bloc using flutter_bloc, we guarantee just a single video plays all at once.
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:video_player/video_player.dart';
class VideoCubit extends Cubit<int?> {
final Map<int, VideoPlayerController> _controllers = {};
VideoCubit() : super(null);
void registerController(int index, VideoPlayerController controller) {
_controllers[index] = controller;
}
void playVideo(int index) {
for (var entry in _controllers.entries) {
if (entry.key == index) {
entry.value.play();
} else {
entry.value.pause();
}
}
emit(index);
}
void stopVideo() {
for (var controller in _controllers.values) {
controller.pause();
}
emit(null);
}
}
Create a new dart file called main.dart
inside the lib
folder.
In this file, we will create a new class VideoGridPage(). This class displays the grid of video items like title, description, and videoUrls.
class VideoGridPage extends StatelessWidget {
final List<VideoItemModel> videoItems = List.generate(
10,
(index) => VideoItemModel(
url: videoUrls[index % videoUrls.length],
title: 'Demo Video $index',
description: 'This is an interactive video of animal $index.',
),
);
static const List<String> videoUrls = [
'https://www.sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4',
];
VideoGridPage({super.key});
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (_) => VideoCubit(),
child: Scaffold(
appBar: AppBar(title: const Text('Flutter Interactive Video Grid'),
automaticallyImplyLeading: false,
centerTitle: true,
backgroundColor: Colors.orangeAccent.shade100,),
body: GridView.builder(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 8,
mainAxisSpacing: 8,
mainAxisExtent: 280, // Consistent height for grid items
),
itemCount: videoItems.length,
itemBuilder: (context, index) {
return VideoGridItem(index: index, videoItem: videoItems[index]);
},
),
),
);
}
}
Create a new dart file called video_grid_item.dart
inside the lib
folder.
In this file, VideoGridItem
class handles the video playback and interaction.
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_interactive_video_grid/video_card.dart';
import 'package:flutter_interactive_video_grid/video_cubit.dart';
import 'package:flutter_interactive_video_grid/video_item_model.dart';
import 'package:video_player/video_player.dart';
class VideoGridItem extends StatefulWidget {
final int index;
final VideoItemModel videoItem;
const VideoGridItem(
{super.key, required this.index, required this.videoItem});
@override
_VideoGridItemState createState() => _VideoGridItemState();
}
class _VideoGridItemState extends State<VideoGridItem> {
VideoPlayerController? _controller;
bool _isLoading = true;
@override
void initState() {
super.initState();
_initializeController();
}
void _initializeController() {
_controller = VideoPlayerController.network(widget.videoItem.url)
..initialize().then((_) {
if (mounted) {
context
.read<VideoCubit>()
.registerController(widget.index, _controller!);
setState(() {
_isLoading = false;
});
}
});
}
@override
void dispose() {
_controller
?.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return BlocBuilder<VideoCubit, int?>(
builder: (context, playingIndex) {
final isPlaying = playingIndex ==
widget.index;
return GestureDetector(
onPanDown: (_) {
context
.read<VideoCubit>()
.playVideo(widget.index);
},
child: VideoCard(
videoItem: widget.videoItem,
controller: _controller,
isPlaying: isPlaying,
),
);
},
);
}
}
Create a new dart file called video_card.dart
inside the lib
folder.
In this file, we will create a new class VideoCard(). This class encapsulates the entire card UI, delegating its parts to specialized sub-widgets.
import 'package:flutter/material.dart';
import 'package:flutter_interactive_video_grid/video_details.dart';
import 'package:flutter_interactive_video_grid/video_item_model.dart';
import 'package:flutter_interactive_video_grid/video_thumbnail.dart';
import 'package:video_player/video_player.dart';
class VideoCard extends StatelessWidget {
final VideoItemModel videoItem;
final VideoPlayerController? controller;
final bool isPlaying;
const VideoCard({
super.key,
required this.videoItem,
this.controller,
required this.isPlaying,
});
@override
Widget build(BuildContext context) {
return Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
elevation: 4,
child: Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
VideoThumbnail(controller: controller, isPlaying: isPlaying),
VideoDetails(
title: videoItem.title, description: videoItem.description),
],
),
),
);
}
}
Create a new dart file called video_thumbnail.dart
inside the lib
folder.
In this file, we will create a new class VideoThumbnail (). This class displays either the video player or a placeholder image depending on whether the video is initialized and currently playing.
import 'package:flutter/material.dart';
import 'package:video_player/video_player.dart';
class VideoThumbnail extends StatelessWidget {
final VideoPlayerController? controller;
final bool isPlaying;
const VideoThumbnail({super.key,
this.controller,
required this.isPlaying,
});
@override
Widget build(BuildContext context) {
return Expanded(
child: Stack(
alignment: Alignment.center,
children: [
if (controller != null && controller!.value.isInitialized && isPlaying)
ClipRRect(
borderRadius: const BorderRadius.vertical(top: Radius.circular(12)),
child: SizedBox(
width: double.infinity,
height: double.infinity,
child: VideoPlayer(controller!),
),
)
else
ClipRRect(
borderRadius: const BorderRadius.vertical(top: Radius.circular(12)),
child: Image.network(
'https://www.sample-videos.com/img/Sample-png-image-200kb.png',
fit: BoxFit.cover,
width: double.infinity,
height: double.infinity,
),
),
],
),
);
}
}
Create a new dart file called video_details.dart
inside the lib
folder.
In this file, we will create a new class VideoDetails(). This class combines the title and description into a single widget for simplicity and better organization.
import 'package:flutter/material.dart';
class VideoDetails extends StatelessWidget {
final String title;
final String description;
const VideoDetails({super.key,
required this.title,
required this.description,
});
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
const SizedBox(height: 4),
Text(
description,
style: const TextStyle(
fontSize: 14,
color: Colors.grey,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
],
),
);
}
}
When we run the application, we ought to get the screen’s output like the underneath screen capture.
![](https://i0.wp.com/flutterexperts.com/wp-content/uploads/2025/02/Untitled-1-3.png?resize=640%2C914&ssl=1)
Code File:
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_interactive_video_grid/splash_screen.dart';
import 'package:flutter_interactive_video_grid/video_cubit.dart';
import 'package:flutter_interactive_video_grid/video_grid_item.dart';
import 'package:flutter_interactive_video_grid/video_item_model.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: Splash(),
);
}
}
class VideoGridPage extends StatelessWidget {
final List<VideoItemModel> videoItems = List.generate(
10,
(index) => VideoItemModel(
url: videoUrls[index % videoUrls.length],
title: 'Demo Video $index',
description: 'This is a interactive video of animal $index.',
),
);
static const List<String> videoUrls = [
'https://www.sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4',
];
VideoGridPage({super.key});
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (_) => VideoCubit(),
child: Scaffold(
appBar: AppBar(title: const Text('Flutter Interactive Video Grid'),
automaticallyImplyLeading: false,
centerTitle: true,
backgroundColor: Colors.orangeAccent.shade100,),
body: GridView.builder(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 8,
mainAxisSpacing: 8,
mainAxisExtent: 280, // Consistent height for grid items
),
itemCount: videoItems.length,
itemBuilder: (context, index) {
return VideoGridItem(index: index, videoItem: videoItems[index]);
},
),
),
);
}
}
Conclusion:
In the article, I have explained the Interactive Video Grid in a flutter; you can modify this code according to your choice. This was a small introduction to Interactive Video Grid On User Interaction from my side, and it’s working using Flutter.
I hope this blog will provide you with sufficient information on Trying the Interactive Video Grid in your flutter projects. We will show you what the Introduction is. Make a demo program for working on an Interactive Video Grid Using the video_player and flutter_bloc package in your Flutter applications. So please try it.
❤ ❤ Thanks for reading this article ❤❤
If I got something wrong? Let me know in the comments. I would love to improve.
Clap 👏 If this article helps you.
Github:
Full source code of Flutter Interactive Video Grid:
GitHub – flutter-devs/flutter_interactive_video_grid
Contribute to flutter-devs/flutter_interactive_video_grid development by creating an account on GitHub.github.com
Feel free to connect with us:
And read more articles from FlutterDevs.com.
FlutterDevs team of Flutter developers to build high-quality and functionally-rich apps. Hire a flutter developer for your cross-platform Flutter mobile app project on an hourly or full-time basis as per your requirement! You can connect with us on Facebook, GitHub, Twitter, and LinkedIn for any flutter-related queries.
We welcome feedback and hope you share what you’re working on using #FlutterDevs. We truly enjoy seeing how you use Flutter to build beautiful, interactive web experiences.
![](https://i0.wp.com/flutterexperts.com/wp-content/uploads/2024/12/0sDg9epxafARP-CG0-3.png?resize=640%2C256&ssl=1)