Issue
I have data coming from a stream mainly a queue and current mediaItem
of the queue. So the mediaItem
is always changing.
I got the index using
index = queue.indexOf(mediaItem);
now I want to set the carousel’s current page to my index, I added the index on the initialPage
of the Carousel but it works only once when the index changes it doesn’t change the current page.
My Stream looks like this
//this stream is initialized inside initState()
stream = Rx.combineLatest3<List<MediaItem>, MediaItem, PlaybackState, ScreenState>(
AudioService.queueStream,
AudioService.currentMediaItemStream,
AudioService.playbackStateStream,
(queue, mediaItem, playbackState) => ScreenState(queue, mediaItem, playbackState)
);
Scaffold(
body: new Center(
child: StreamBuilder<ScreenState>(
stream: stream,
builder: (context, snapshot) {
final screenState = snapshot.data;
final queue = screenState?.queue;
final mediaItem = screenState?.mediaItem;
final state = screenState?.playbackState;
final basicState = state?.basicState ?? BasicPlaybackState.none;
int index = queue?.indexWhere((MediaItem mediaItemX){return (mediaItem?.id == mediaItemX.id);});
return (queue!=null&& mediaItem!=null && basicState != null && index != null)
? mainView(queue, mediaItem, basicState, state, index)
: Container(
child: Center(
child: SpinKitWave(
color: Colors.white70,
),
),
);
},
),
),
),
Main view
Widget mainView(List<MediaItem> queue, MediaItem mediaItemX, BasicPlaybackState basicState, PlaybackState state, int index){
return CarouselSlider.builder(
itemCount: queue.length,
initialPage: queue.indexOf(mediaItemX),//only works first time
itemBuilder: (BuildContext context, int itemIndex) {
Stack(
children: <Widget>[
ClipRRect(
borderRadius: BorderRadius.circular(8.0),
child: Container(
padding: EdgeInsets.fromLTRB(0,0,0,0),
child: CachedNetworkImage(
height: ScreenUtil().setWidth(1200),
width: ScreenUtil().setWidth(1200),
imageUrl: queue[itemIndex].artUri,
fit: BoxFit.cover,
placeholder: (context, url) => new SpinKitWave(color: Colors.white30, size: 30.0,),
errorWidget: (context, url, error) => new Image.asset(
'images/addplaylist.png',
color: Colors.white30,
),
),
)
)
],
),
}
);
}
The issue is when mediaItem
changes from another place, the carousel is needed to change its index based on the stream change of data, In other words, a functionality almost same as currentPage inside Carousel so that every time index changes then the currentPage
is set to the new data from the stream or to control the Carousel from the stream.
A solution or a hint with an example is highly appreciated.
Additional Information: I am using carousel_slider: ^1.4.1
Solution
initialPage works properly with empty containers (see code below), seems to me that is missing some key
maybe in cached image network or your container, try put a UniqueKey()
to ensure that widget tree will detect the change when new snapshot comes…
Example working with StreamBuilder
and slider:
import 'dart:async';
import 'dart:math';
import 'package:carousel_slider/carousel_slider.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(body: MyHomePage()),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final StreamController sc = StreamController();
final rng = Random();
final containers = [
Container(color: Colors.pink),
Container(color: Colors.black),
Container(color: Colors.yellow),
Container(color: Colors.brown),
];
@override
void initState() {
super.initState();
Timer.periodic(
Duration(seconds: 5),
(t) {
sc.add(rng.nextInt(containers.length));
},
);
}
@override
Widget build(BuildContext context) {
return StreamBuilder(
stream: sc.stream,
builder: (context, snapshot) {
if (snapshot.hasData == false) {
return CircularProgressIndicator();
}
return Container(
child: mainView(containers, containers[snapshot.data]),
);
},
);
}
Widget mainView(
List<Container> queue,
Container mediaItemX,
) {
return CarouselSlider.builder(
itemCount: queue.length,
initialPage: queue.indexOf(mediaItemX), //only works first time
itemBuilder: (BuildContext context, int itemIndex) {
print('changed');
return mediaItemX;
},
);
}
}
Answered By – Renê Guilherme Nucci
Answer Checked By – Terry (FlutterFixes Volunteer)