Управление Каруселью Slider от Stream (Флаттер) - PullRequest
0 голосов
/ 10 февраля 2020

У меня есть данные, поступающие из потока, в основном из очереди, и текущий 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

1 Ответ

1 голос
/ 18 февраля 2020

initialPage работает должным образом с пустыми контейнерами (см. Код ниже), мне кажется, что не хватает некоторых key, возможно, в кэшированном изображении netowork или в вашем контейнере, попробуйте поставить UniqueKey(), чтобы дерево виджетов обнаруживало изменения, когда приходит новый snapthos ...

Пример работы с 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;
      },
    );
  }
}
...