从 Stream (Flutter) 控制轮播滑块
Posted
技术标签:
【中文标题】从 Stream (Flutter) 控制轮播滑块【英文标题】:Controlling Carousel Slider from Stream (Flutter) 【发布时间】:2020-05-25 12:37:17 【问题描述】:我有来自流的数据,主要是队列和队列的当前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
从另一个地方改变时,轮播需要根据数据流的变化来改变它的索引,也就是说,在Carousel里面的功能几乎和currentPage一样,这样每次索引都会改变currentPage
设置为来自流的新数据或控制来自流的轮播。
非常感谢带有示例的解决方案或提示。
附加信息:我正在使用carousel_slider: ^1.4.1
【问题讨论】:
考虑将pageController
传递给您的CarousselSlider
,并让您的流修改该控制器
@RémiRousselet 你能举例说明如何做到这一点吗?因为轮播仍然必须在 StreamBuilder 内部,并且要控制使用 pageController,所以必须已经构建了轮播。
如here 所述,因为StreamBuilder 是一个Widget,它基于与Stream 交互的最新快照构建自身,它应该在索引更改时更改页面直接从流中重建 carouselSlider,包括使用新索引值的 initialPage 数据。
我不确定它是否与this 有关,我已经尝试过修复,似乎不起作用。
更改initialPage
不会更改当前页面。 initialPage
仅用于第一次渲染,之后被忽略
【参考方案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;
,
);
【讨论】:
以上是关于从 Stream (Flutter) 控制轮播滑块的主要内容,如果未能解决你的问题,请参考以下文章