从 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;
      },
    );
  }
}