从 Stream (Flutter) 控制 Carousel Slider
Controlling Carousel Slider from Stream (Flutter)
我有来自流的数据,主要是队列和队列的当前 mediaItem
。所以 mediaItem
总是在变化。
我使用
获得了索引
index = queue.indexOf(mediaItem);
现在我想将轮播的当前页面设置为我的索引,我在轮播的 initialPage
上添加了索引,但是当索引更改时它只工作一次,它不会更改当前页面。
我的流看起来像这样
//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,
),
),
);
},
),
),
),
主视图
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,
),
),
)
)
],
),
}
);
}
问题是当mediaItem
从另一个地方改变时,轮播需要根据数据流的变化来改变它的索引,换句话说,一个几乎与轮播内部的currentPage相同的功能,以便每个时间索引更改然后 currentPage
设置为来自流的新数据或控制来自流的轮播。
非常感谢带有示例的解决方案或提示。
附加信息:我正在使用 carousel_slider: ^1.4.1
initialPage 与空容器一起正常工作(见下面的代码),在我看来缺少一些 key
也许在缓存图像网络或你的容器中,尝试放置一个 UniqueKey()
以确保小部件树将在新快照到来时检测到变化...
使用 StreamBuilder
和滑块的示例:
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;
},
);
}
}
我有来自流的数据,主要是队列和队列的当前 mediaItem
。所以 mediaItem
总是在变化。
我使用
index = queue.indexOf(mediaItem);
现在我想将轮播的当前页面设置为我的索引,我在轮播的 initialPage
上添加了索引,但是当索引更改时它只工作一次,它不会更改当前页面。
我的流看起来像这样
//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,
),
),
);
},
),
),
),
主视图
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,
),
),
)
)
],
),
}
);
}
问题是当mediaItem
从另一个地方改变时,轮播需要根据数据流的变化来改变它的索引,换句话说,一个几乎与轮播内部的currentPage相同的功能,以便每个时间索引更改然后 currentPage
设置为来自流的新数据或控制来自流的轮播。
非常感谢带有示例的解决方案或提示。
附加信息:我正在使用 carousel_slider: ^1.4.1
initialPage 与空容器一起正常工作(见下面的代码),在我看来缺少一些 key
也许在缓存图像网络或你的容器中,尝试放置一个 UniqueKey()
以确保小部件树将在新快照到来时检测到变化...
使用 StreamBuilder
和滑块的示例:
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;
},
);
}
}