How to play a List of video carousel? - flutter

I want to create a List of video carousel, something similar to a social media platform.
I tried making video carousel using flutter_swiper and video_player. and created a list using inview_notifier_list 's autoplay example, But unable to get the desired output.
class VideoList extends StatefulWidget {
#override
_VideoListState createState() => _VideoListState();
}
class _VideoListState extends State<VideoList> {
List<String> videoList = [
'https://flutter.github.io/assets-for-api-docs/assets/videos/butterfly.mp4',
'https://flutter.github.io/assets-for-api-docs/assets/videos/butterfly.mp4',
'https://flutter.github.io/assets-for-api-docs/assets/videos/butterfly.mp4',
'https://flutter.github.io/assets-for-api-docs/assets/videos/butterfly.mp4',
];
String videoToPlay;
#override
void initState() {
super.initState();
videoToPlay = videoList[0];
}
#override
Widget build(BuildContext context) {
return Stack(
fit: StackFit.expand,
children: <Widget>[
InViewNotifierList(
scrollDirection: Axis.vertical,
initialInViewIds: ['0'],
isInViewPortCondition:
(double deltaTop, double deltaBottom, double viewPortDimension) {
return deltaTop < (0.5 * viewPortDimension) &&
deltaBottom > (0.5 * viewPortDimension);
},
itemCount: 5,
builder: (context, index) => Container(
width: double.infinity,
height: 300.0,
alignment: Alignment.center,
margin: EdgeInsets.symmetric(vertical: 50.0),
child: SizedBox(
height: 300,
width: double.infinity,
child: Swiper(
onIndexChanged: (i) {
setState(() {
videoToPlay = videoList[i];
});
},
itemCount: videoList.length,
itemBuilder: (context, index) => LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
final InViewState inViewState =
InViewNotifierList.of(context);
inViewState.addContext(context: context, id: '$index');
return AnimatedBuilder(
animation: inViewState,
builder: (BuildContext context, Widget child) {
return VideoWidget(
play: inViewState.inView('$index'),
url: videoToPlay);
},
);
},
),
),
),
),
),
Align(
alignment: Alignment.center,
child: Container(
height: 1.0,
color: Colors.redAccent,
),
)
],
);
}
}
and below is my video class, where the video player is initialized
class VideoWidget extends StatefulWidget {
final String url;
final bool play;
const VideoWidget({Key key, #required this.url, #required this.play})
: super(key: key);
#override
_VideoWidgetState createState() => _VideoWidgetState();
}
class _VideoWidgetState extends State<VideoWidget> {
VideoPlayerController _controller;
Future<void> _initializeVideoPlayerFuture;
#override
void initState() {
super.initState();
_controller = VideoPlayerController.network(widget.url);
_initializeVideoPlayerFuture = _controller.initialize().then((_) {
// Ensure the first frame is shown after the video is initialized, even before the play button has been pressed.
setState(() {});
});
if (widget.play) {
_controller.play();
_controller.setLooping(true);
}
}
#override
void didUpdateWidget(VideoWidget oldWidget) {
if (oldWidget.play != widget.play) {
if (widget.play) {
_controller.play();
_controller.setLooping(true);
} else {
_controller.pause();
}
}
super.didUpdateWidget(oldWidget);
}
#override
void dispose() {
_controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: _initializeVideoPlayerFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return VideoPlayer(_controller);
} else {
return Center(
child: CircularProgressIndicator(),
);
}
},
);
}
}
Could someone please help out, What should be the correct approach?

So here I am sharing my solution How did i manged to create a List of video cousrsel.
Widget build(BuildContext context) {
return Stack(
fit: StackFit.expand,
children: <Widget>[
InViewNotifierList(
scrollDirection: Axis.vertical,
initialInViewIds: ['0'],
isInViewPortCondition:
(double deltaTop, double deltaBottom, double viewPortDimension) {
return deltaTop < (0.5 * viewPortDimension) &&
deltaBottom > (0.5 * viewPortDimension);
},
itemCount: 5,
builder: (context, index) => Container(
width: double.infinity,
height: 300.0,
alignment: Alignment.center,
margin: EdgeInsets.symmetric(vertical: 50.0),
child: LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
print('layout called');
final InViewState inViewState = InViewNotifierList.of(context);
inViewState.addContext(context: context, id: '$index');
return PageView.builder(
itemCount: videoList.length,
itemBuilder: (context, indexPage) => AnimatedBuilder(
animation: inViewState,
builder: (BuildContext context, Widget child) {
return VideoWidget(
play: inViewState.inView('$index'),
url: videoList[indexPage]);
},
),
);
},
),
),
),
Align(
alignment: Alignment.center,
child: Container(
height: 1.0,
color: Colors.redAccent,
),
)
],
);
}
}
where my video List is the list of URL of videos.

Related

Loading page for ListView builder flutter

Hello I would like to have a loading page before all the list is created. To display this list, I get the request info in php and I create cards one by one. The problem is that when the user come on the application, there is a lot of loading round because I put "return CircularProgressIndicator()", I would like that we are on a waiting page until all the cards are not loaded
I tried to set variables and pass them to false until all the cards are loaded but I can't get on this loading page
Here is the code of my page
Future<String> getDataSearch(text, index) async {
if (index != "ff") {
var theUrl =
Uri.parse("https://xf8s7auoez.preview.infomaniak.website/getdata.php");
var res = await http.post(theUrl, body: {
"index": index.toString(),
"post": "index",
"file": "get_data",
});
Map<String, dynamic> data = jsonDecode(res.body);
if (text == 1) {
return data["type"];
} else if (text == 2) {
return data["taille"];
} else if (text == 3) {
return data["prix"];
} else if (text == 5) {
return data["image"];
} else if (text == 6) {
return data["description"];
}
}
var theUrl =
Uri.parse("https://xf8s7auoez.preview.infomaniak.website/getdata.php");
var res = await http.post(theUrl, body: {
"post": "rows",
"file": "get_data",
});
print(res.body);
return res.body;
}
class Type extends StatelessWidget {
Type(this.index);
final int index;
#override
Widget build(context) {
return FutureBuilder<String>(
// future: getUserType(index),
future: getDataSearch(1, index),
builder: (context, AsyncSnapshot<String> snapshot) {
if (snapshot.hasData) {
return Text(snapshot.data!);
} else {
return SizedBox(width: 10, height: 10, child: Container());
}
});
}
}
class Description extends StatelessWidget {
Description(this.index);
final int index;
#override
Widget build(context) {
return FutureBuilder<String>(
// future: getUserType(index),
future: getDataSearch(6, index),
builder: (context, AsyncSnapshot<String> snapshot) {
if (snapshot.hasData) {
return Text(snapshot.data!);
} else {
return SizedBox(width: 10, height: 10, child: Container());
}
});
}
}
class Taille extends StatelessWidget {
Taille(this.index);
final int index;
#override
Widget build(context) {
return FutureBuilder<String>(
// future: getUserType(index),
future: getDataSearch(2, index),
builder: (context, AsyncSnapshot<String> snapshot) {
if (snapshot.hasData) {
return Text(snapshot.data!);
} else {
return SizedBox(width: 10, height: 10, child: Container());
}
});
}
}
class Prix extends StatelessWidget {
Prix(this.index);
final int index;
#override
Widget build(context) {
return FutureBuilder<String>(
//future: getAge(index),
future: getDataSearch(3, index),
builder: (context, AsyncSnapshot<String> snapshot) {
if (snapshot.hasData) {
String bio = snapshot.data.toString();
return Text(bio);
} else {
return SizedBox(width: 10, height: 10, child: Container());
}
});
}
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Mediester',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: RefreshIndicatorView(),
);
}
}
class RefreshIndicatorView extends StatefulWidget {
const RefreshIndicatorView({Key? key}) : super(key: key);
#override
_RefreshIndicatorViewState createState() => _RefreshIndicatorViewState();
}
class _RefreshIndicatorViewState extends State<RefreshIndicatorView> {
int initNumber = 1;
int selectedValue = 1;
final GlobalKey<ScaffoldState> _key = GlobalKey();
#override
initState() {
getDataSearch(4, "ff").then((String result) {
if (initNumber != int.parse(result)) {
setState(() {
initNumber = int.parse(result);
});
}
});
}
#override
Widget build(BuildContext context) {
return RefreshIndicator(
displacement: 250,
backgroundColor: Color.fromARGB(255, 110, 155, 191),
color: Colors.white,
strokeWidth: 3,
triggerMode: RefreshIndicatorTriggerMode.onEdge,
onRefresh: () async {
await Future.delayed(Duration(milliseconds: 1500));
setState(() {
int debug = 0;
});
},
child: Scaffold(
key: _key,
backgroundColor: Color.fromARGB(255, 110, 155, 191),
appBar: BaseAppBar(),
drawer: createDrawer(context),
body: _buildCardDesign(),
),
);
}
Widget _buildCardDesign() {
Future.delayed(const Duration(milliseconds: 1500), () {
if (debugg != 1) {
setState(() {});
debugg = 1;
}
});
return Container(
margin: EdgeInsets.all(5),
child: ListView.builder(
itemCount: initNumber,
shrinkWrap: true,
physics: const BouncingScrollPhysics(
parent: AlwaysScrollableScrollPhysics()),
scrollDirection: Axis.vertical,
prototypeItem: _buildCardView(1),
itemBuilder: (BuildContext context, int index) {
return _buildCardView(index + 1);
}),
);
}
Widget _buildPhoto(index) {
return Container(
child: FutureBuilder<String>(
future: getDataSearch(5, index),
builder: (context, AsyncSnapshot<String> snapshot) {
if (snapshot.hasData) {
return ClipRRect(
borderRadius: BorderRadius.circular(5.0),
child: Image.network(
snapshot.data!,
height: 65.0,
width: 65.0,
fit: BoxFit.cover,
),
);
} else {
return CircularProgressIndicator.adaptive();
}
}));
}
Widget _buildCardView(index) {
return Container(
width: MediaQuery.of(context).size.width,
child: Container(
margin: EdgeInsets.all(10),
height: 100,
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(Radius.circular(10))),
child: GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ArticlePage(
index, Type(index), Prix(index), Description(index)),
));
},
child: Container(
padding: EdgeInsets.fromLTRB(15, 15, 30, 15),
child: Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
_buildPhoto(index),
//SizedBox(width: 20,),
DefaultTextStyle(
style: TextStyle(
fontSize: 19,
fontWeight: FontWeight.w800,
color: Color.fromARGB(255, 110, 155, 191)),
child: Container(
padding: EdgeInsets.only(left: 40),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
DefaultTextStyle(
child: Container(child: Type(index)),
style: TextStyle(
color: Color.fromARGB(255, 110, 155, 191),
fontSize: 17)),
DefaultTextStyle(
child: Container(
padding: EdgeInsets.only(top: 8),
child: Taille(index)),
style: TextStyle(
color: Color.fromARGB(255, 168, 168, 168)),
),
Container(
padding: EdgeInsets.only(top: 3),
child: Row(
children: [
Prix(index),
Text(" €"),
],
)),
],
),
),
),
],
),
),
),
),
);
}
}
This can be accomplished using a FutureBuilder. In your RefreshIndicatorView class, the _buildCardDesign widget is currently calling your future, and then building the ListView. Instead, try creating one async function that holds the logic for retrieving the data, and a separate class for the widget that is only responsible for building the widget. Then, you can call the future in the FutureBuilder and show your loading page until it has completed.
In the FutureBuilder, pass your function as the argument to future. Then you can use the variable snapshot to check the status of the future. In your builder function, simply check if(snapshot.hasData), and show the loading page or the listView widget accordingly.
Edit: Here's a simple example that retrieves a List<String> and puts one String in each card. Your new function and widget class would look like this:
List<String> _getStrings() async {
//Async logic here
...
}
Widget MyCard extends StatelessWidget {
final String displayText;
myCard(this.displayText);
#override
Widget build(BuildContext context) {
return Text(displayText);
}
}
And in the home page of your MyApp, you can use something like this for the build method:
FutureBuilder<List<String>>(
future: _getStrings,
builder: (BuildContext context, AsyncSnapshot<List<String>> snapshot) {
if(snapshot.hasData) {
return ListView.builder(
itemBuilder: (BuildContext context, int index) => MyCard(snapshot.data[index])
...
);
} else {
return MyLoadingScreen();
}
});

I want to scroll up after the all childs of ListView have been scrolled up, parent widget of listview is SingleChildScrollView in flutter

I have SingleChildScrollView as a parent and in that, I have two listviews each list view is wrapped with SizedBox with a specific height (like 700), what I want is, when I scroll up all the views that are in the first list, the first Listview should scroll up and then I'll be able to scroll next Listview, Please have a look into the code below.
Your help means a lot to me.
Thank you in advance.
Note: I'm getting this required behavior in chrome but not on a mobile device
SingleChildScrollView( child: Column(children: [
SizedBox(
height: 700,
child:ListView.builder(
itemCount:
20, itemBuilder: (context, index) {
return const ListTile(leading: Icon(Icons.icecream,
color: Colors.amber,), title: Text("Ice Cream"),);
},),
),
SizedBox(
height: 300,
child: ListView.builder(
itemCount: 20, itemBuilder: (context, index) {
return const ListTile(
leading: Icon(Icons.cake, color: Colors.red,),
title: Text("Cake"),);
},),
),
],),)
You Can Do something like this on the Controllers:
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class ScrollingBehaviourInDart extends StatefulWidget {
const ScrollingBehaviourInDart({Key? key}) : super(key: key);
#override
State<ScrollingBehaviourInDart> createState() =>
_ScrollingBehaviourInDartState();
}
class _ScrollingBehaviourInDartState extends State<ScrollingBehaviourInDart> {
late ScrollController _sc1;
late ScrollController _sc2;
late ScrollController _sc3;
#override
void initState() {
_sc1 = ScrollController();
_sc2 = ScrollController();
_sc3 = ScrollController();
var _pr = Provider.of<MyScrollProvider>(context, listen: false);
_sc1.addListener(() {
log("SC1::::::::::: " + _sc1.position.pixels.toString());
if (_sc1.position.pixels == _sc1.position.minScrollExtent) {
print("OK");
_pr.changePhysics(enableScrolling: true);
}
});
_sc2.addListener(() {
if (_sc2.offset == _sc2.position.maxScrollExtent) {
_pr.changePhysics(enableScrolling: false);
log("YAAA");
}
});
_sc3.addListener(() {
log("SC3::::::::::: " + _sc3.position.pixels.toString());
});
super.initState();
}
#override
void dispose() {
_sc1.dispose();
_sc2.dispose();
_sc3.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
var _size = MediaQuery.of(context).size;
return SafeArea(
child: Scaffold(
backgroundColor: Colors.white.withOpacity(0.8),
body: SizedBox(
height: _size.height,
child: Consumer<MyScrollProvider>(
builder: (context, myScrollProvider, _) => SingleChildScrollView(
controller: _sc1,
child: Column(
children: [
SizedBox(
height: _size.height * 0.5,
child: ListView.builder(
controller: _sc2,
physics: myScrollProvider.enablePrimaryScroll
? const AlwaysScrollableScrollPhysics()
: const NeverScrollableScrollPhysics(),
itemCount: 20,
shrinkWrap: true,
itemBuilder: (context, index) {
return const ListTile(
leading: Icon(
Icons.icecream,
color: Colors.amber,
),
title: Text("Ice Cream"),
);
},
),
),
ListView.builder(
itemCount: 20,
controller: _sc3,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) {
return const ListTile(
leading: Icon(
Icons.cake,
color: Colors.red,
),
title: Text("Cake"),
);
},
),
],
),
),
),
),
),
);
}
}
class MyScrollProvider extends ChangeNotifier {
var enablePrimaryScroll = true;
changePhysics({required bool enableScrolling}) {
enablePrimaryScroll = enableScrolling;
notifyListeners();
}
}
maybe you can use Stickyheader.
import 'package:sticky_headers/sticky_headers.dart';
ListView(
shrinkwarp:true,
children:[
StickyHeader(
head: Text('List 1 '),
content : ListView.builder(
physics: const ClampingScrollPhysics(), // use this for clamping scroll
itemBuilder: (context, idx) => Container(),
itemCount:5,
)
StickyHeader(
head: Text('List 2 '),
content : ListView.builder(
physics: const ClampingScrollPhysics(), // use this for clamping scroll
itemBuilder: (context, idx) => Container(),
itemCount:5,
)
]
}
There are many easy ways to handle this situation as stated by many other developers. I have created an Example class with ScrollController and AbsordPointer classes to achieve the required behavior.
Sample
class Example extends StatefulWidget {
const Example({super.key});
#override
State<Example> createState() => _ExampleState();
}
class _ExampleState extends State<Example> {
late ScrollController scrollController;
var reachedAtEnd = false;
#override
void initState() {
super.initState();
scrollController =ScrollController()..addListener(() {
if (scrollController.position.pixels == scrollController.position.maxScrollExtent) {
reachedAtEnd = true;
setState(() {
});
}
},);
}
#override
Widget build(BuildContext context) {
return SingleChildScrollView(
physics: NeverScrollableScrollPhysics(),
child: Column(
children: [
SizedBox(
height: 700,
child: ListView.builder(
controller: scrollController,
itemCount: 20,
itemBuilder: (context, index) {
return const ListTile(
leading: Icon(
Icons.icecream,
color: Colors.amber,
),
title: Text("Ice Cream"),
);
},
),
),
SizedBox(
height: 300,
child: AbsorbPointer(
absorbing: !reachedAtEnd,
child: ListView.builder(
itemCount: 20,
itemBuilder: (context, index) {
return const ListTile(
leading: Icon(
Icons.cake,
color: Colors.red,
),
title: Text("Cake"),
);
},
),
),
),
],
),
);
}
}
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
// this variable determnines whether the back-to-top button is shown or not
bool _showBackToTopButton = false;
// scroll controller
late ScrollController _scrollController;
#override
void initState() {
_scrollController = ScrollController()
..addListener(() {
setState(() {
print(_scrollController.offset);
if (_scrollController.offset >= 400) {
_showBackToTopButton = true;
// _scrollToTop();
// show the back-to-top button
} else {
_showBackToTopButton = false; // hide the back-to-top button
}
});
});
super.initState();
}
#override
void dispose() {
_scrollController.dispose(); // dispose the controller
super.dispose();
}
// This function is triggered when the user presses the back-to-top button
void _scrollToTop() {
_scrollController.animateTo(0,
duration: const Duration(seconds: 3), curve: Curves.linear);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('com'),
),
body: ListView.builder(
controller: _scrollController,
itemCount: 40,
itemBuilder: (context, index) {
print(index);
if (index == 39) {
_scrollToTop();
}
return const ListTile(
leading: Icon(
Icons.icecream,
color: Colors.amber,
),
title: Text(' Ice Cream'),
);
},
),
);
}
}

FutureBuilder operated without initState in flutter

I work with FutureBuilder to view a set of data through GridView by FutureBuilder but there are one problem the data is view without put method in initState().I don't know why it works without putting it in initState().
full code:
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
void initState() {
super.initState();
}
bool showicon = false;
var apiURL;
Future getdataCat() async {
setState(() {
showicon = true;
});
apiURL = '***********************';
var response = await http.post(Uri.parse(apiURL));
var responsebody = jsonDecode(response.body);
if (responsebody.length > 0) {
return responsebody;
} else {
showicon = false;
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
children: <Widget>[
Flexible(
child: FutureBuilder(
future: getdataCat(),
builder: (context, AsyncSnapshot snapshot) {
if (!snapshot.hasData) {
// still waiting for data to come
return showicon
? Center(
child: CircularProgressIndicator(
color: Colors.black,
))
: SizedBox(
height: 10,
child: Center(
child: Image.asset(
'assets/data.png',
)));
} else if (snapshot.hasData &&
snapshot.data.isEmpty &&
snapshot.data <= 0) {
return SizedBox(
height: 10,
child: Center(
child: Image.asset(
'assets/data.png',
)));
} else {
return GridView.builder(
physics: ScrollPhysics(),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2, childAspectRatio: 3.4),
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
return Container(
child: Card(
child: Column(
children: <Widget>[
Flexible(
child: GestureDetector(
child: Column(children: <Widget>[
Center(
child: Text(
"${snapshot.data[index]['name']}"))
]),
)),
],
),
),
);
},
);
}
},
),
)
],
),
),
);
}
}
As you can see I not make any thing in initState() but it's still working.
I need to stop it if I don't put it in initState().Because I need to run a different function before it.
I prefer this way. You can check Randal L. Schwartz video
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
late final Future<List<int>?> myFuture;
#override
void initState() {
super.initState();
myFuture = getCatData();
}
Future<List<int>?> getCatData() async {
await Future.delayed(Duration(seconds: 2));
//your operations
return [1, 2, 5];
// return [];
}
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(onPressed: () {
setState(() {});
}),
body: Center(
child: Column(
children: <Widget>[
Flexible(
child: FutureBuilder<List<int>?>(
future: myFuture,
builder: (context, AsyncSnapshot snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const CircularProgressIndicator();
}
if (snapshot.hasError) {
return Text("Error ${snapshot.error}");
}
if (!snapshot.hasData) {
return Text("no Data found");
}
if (snapshot.data!.isEmpty) {
return Text("Empty found");
}
if (snapshot.hasData) {
return GridView.builder(
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 3.4,
),
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
return Container(
child: Text(snapshot.data[index].toString()));
},
);
}
return Text("NA");
},
),
)
],
),
),
);
}
}
Point of FutureBuilder is to run a function that will return with the data you want to use to build your widgets.
You already call your method in the FutureBuilder:
FutureBuilder(
future: getdataCat(),
builder: (context, AsyncSnapshot snapshot) {...}
)

How to make flutter_vlc_player work with data from an api

I'm working with an api that returns some tv livestreams . But i can't really figure how to work around with the flutter_vlc_player which is specifically what i want to use. its documentation
I've tried but i'm getting the error _videoPlayerController has not been initialized
Here is my code
import 'package:flutter/material.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:flutter_vlc_player/flutter_vlc_player.dart';
class Home extends StatefulWidget {
const Home({Key? key}) : super(key: key);
#override
State<Home> createState() => _HomeState();
}
class _HomeState extends State<Home> {
Future<List<dynamic>> fetchMedia() async {
final result = await http
.get(Uri.parse('https://iptv-org.github.io/api/streams.json'));
return json.decode(result.body);
}
String _name(dynamic media) {
return media['channel'];
}
String _location(dynamic media) {
return media['url'];
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: FutureBuilder<List<dynamic>>(
future: fetchMedia(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if(snapshot.hasData){
return ListView.builder(
padding: EdgeInsets.all(8),
itemCount: 10,
itemBuilder: (BuildContext context, int index){
late VlcPlayerController _videoPlayerController;
#override
void dispose() async {
super.dispose();
await _videoPlayerController.stopRendererScanning();
await _videoPlayerController.dispose();
}
String url = _location(snapshot.data[index]);
#override
void initState() {
super.initState();
_videoPlayerController = VlcPlayerController.network(
url,
autoPlay: false,
options: VlcPlayerOptions(),
);
}
return
Card(
child: Column(
children: <Widget>[
ListTile(
leading: Icon(Icons.tv),
title: Text(_name(snapshot.data[index])),
subtitle:SizedBox(
child: VlcPlayer(
controller: _videoPlayerController,
aspectRatio: 16/ 9,
placeholder: Center(child: CircularProgressIndicator()),
),),)],
),):});
}else {
return Center(child: CircularProgressIndicator());
}
},
),
),
);
}
}
What i want to achieve is that for each media url of a particular index to be passed into the VlcPlayerController.network()
Can somebody help please !!
Scaffold(
body: FutureBuilder<List<dynamic>>(
future: fetchMedia(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
return ListView.builder(
padding: const EdgeInsets.all(8),
itemCount: 10,
itemBuilder: (BuildContext context, int index) {
String url = _location(snapshot.data[index]);
VlcPlayerController videoPlayerController =
VlcPlayerController.network(
url,
autoPlay: false,
options: VlcPlayerOptions(),
);
#override
void dispose() async {
super.dispose();
await videoPlayerController.stopRendererScanning();
await videoPlayerController.dispose();
}
#override
void initState() {
super.initState();
videoPlayerController = VlcPlayerController.network(
url,
autoPlay: false,
options: VlcPlayerOptions(),
);
}
return Card(
child: Column(
children: <Widget>[
ListTile(
leading: Icon(Icons.tv),
title: Text(_name(snapshot.data[index])),
subtitle: SizedBox(
child: VlcPlayer(
controller: videoPlayerController,
aspectRatio: 16 / 9,
placeholder:
Center(child: CircularProgressIndicator()),
),
),
)
],
),
);
});
} else {
return Center(child: CircularProgressIndicator());
}
},
),
);
Here is the updated code for flutter_vlc_player Please do make sure the android minimum SDK to 20 otherwise the project will not run.

Dynamic content PageView is not working in flutter

I tried to add dynamic content in pageview but the view of pageview is not showing.
class HomeFragment extends StatefulWidget {
#override
_HomeFragmentState createState() => _HomeFragmentState();
}
class _HomeFragmentState extends State<HomeFragment> {
List<String> pagerItems = new List();
#override
void initState() {
populatePager();
}
void populatePager() {
pagerItems.add(
"https://ecouponshop.com/wp-content/uploads/2016/04/20-848x470.jpg");
pagerItems.add(
"https://rukminim1.flixcart.com/flap/960/960/image/eb7785.jpg?q=50");
pagerItems.add(
"https://zamroo.s3.ap-south-1.amazonaws.com/images/product-images/home-garden/washing-machines/medium/20170803092151-23218.jpg");
setState(() {
pagerItems;
});
}
#override
Widget build(BuildContext context) {
return Container(
height: double.infinity,
child: Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Container(
height: 200.0,
child: pager(),
)
],
),
),
);
}
Widget pager() {
return PageView.builder(
itemCount: pagerItems.length,
physics: BouncingScrollPhysics(),
itemBuilder: (BuildContext context, int index) {
pagerBody(context, index);
});
}
}
There are couple of mistakes in your code, like you forgot super.initState(), you were not returning any widget from itemBuilder. And you were unnecessarily using pager.items inside setState. Here is the correct code.
class HomeFragment extends StatefulWidget {
#override
_HomeFragmentState createState() => _HomeFragmentState();
}
class _HomeFragmentState extends State<HomeFragment> {
List<String> pagerItems = new List();
#override
void initState() {
super.initState(); // you forgot this
populatePager();
}
void populatePager() {
setState(() {
pagerItems.add("https://ecouponshop.com/wp-content/uploads/2016/04/20-848x470.jpg");
pagerItems.add("https://rukminim1.flixcart.com/flap/960/960/image/eb7785.jpg?q=50");
pagerItems.add("https://zamroo.s3.ap-south-1.amazonaws.com/images/product-images/home-garden/washing-machines/medium/20170803092151-23218.jpg");
});
}
#override
Widget build(BuildContext context) {
return Container(
height: double.infinity,
child: Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Container(
height: 200.0,
child: pager(),
)
],
),
),
);
}
Widget pager() {
return PageView.builder(
itemCount: pagerItems.length,
physics: BouncingScrollPhysics(),
itemBuilder: (BuildContext context, int index) {
return pagerBody(context, index); // you forgot this
},
);
}
}