Управление состоянием onBackPressed в блоке Flutter

Итак, у меня есть простой список, который можно щелкнуть, и он переходит на экран DetailScreen. Проблема, с которой я сталкиваюсь, заключается в том, что когда я возвращаюсь с экрана DetailScreen, как я могу управлять этим состоянием, чтобы сохранить последний список?

Блок

if (event is GetNews && !_hasReachedMax(state)) {
      try {
        if (currentState is NewsInitial) {
          final news = await fetchNews(event.cat, pageNumber);
          yield NewsLoaded(news, false);
        }
        if (currentState is NewsLoaded) {
          pageNumber++;
          final news = await fetchNews(event.cat, pageNumber);
          yield news.isEmpty
              ? currentState.copyWith(hasReachedMax: true)
              : NewsLoaded(currentState.node + news, false);
        }
      } catch (error) {
        print(error);
        yield NewsError("Error fetching news" + error);
      }
    } else if (event is GetDetailedNews) {
      try {
        final filter = await fetchDetailedNews(event.id);
        yield DetailedNewsLoaded(filter);
      } catch (error) {
        yield NewsError("Couldn't fetch news : $error");
      }
    }

Присоединение мероприятия к блоку

  @override
  void initState() {
    super.initState();
    _postBloc = BlocProvider.of<NewsBloc>(context)
      ..add(GetNews(widget.cat));
  }

BlocBuilder

OnBackPressed Я просто придерживаюсь else, так как не знаю, как управлять состоянием

    return BlocBuilder<NewsBloc, NewsState>(builder: (context, state) {
      if (state is NewsLoaded) {
          return ListView.builder(
              controller: _scrollController,
              itemCount: state.hasReachedMax
                  ? state.node.length
                  : state.node.length + 1,
              itemBuilder: (context, index) {
                fullList = state.node;
                print("list: ${state.node} \nlength: ${state.node
                    .length} \nindex: $index \n--------------");
                return index >= state.node.length ?
                BottomLoader() :
                listViews(context, state.node[index], index);
              });
      }
      else if (state is NewsError) {
          return Center(
              child: Container(
                child: Text(state.message),
              ));
      }
      else {
        return Center(child: CircularProgressIndicator(),);
      }
    });

состояния

abstract class NewsState extends Equatable {
  const NewsState();

  @override
  List<Object> get props => [];
}

class NewsInitial extends NewsState {
  const NewsInitial();

  @override
  List<Object> get props => [];
}

class NewsLoading extends NewsState {
  const NewsLoading();

  @override
  List<Object> get props => [];
}
class NewsLoaded extends NewsState {
  final List<Node> node;
  final bool hasReachedMax;

  NewsLoaded(this.node, this.hasReachedMax);

  NewsLoaded copyWith({List<Node> node, bool hasReachedMax}) {
    return NewsLoaded(node ?? this.node, hasReachedMax ?? this.hasReachedMax);
  }

  @override
  List<Object> get props => [node];
}

class DetailedNewsLoaded extends NewsState {
  final List<Node> node;

  DetailedNewsLoaded(this.node);

  @override
  List<Object> get props => [node];
}
}

На подробном экране я добавляю событие GetDetailScreen, и это событие остается, когда onBackPressed

  @override
  void initState() {
    BlocProvider.of<NewsBloc>(context)
      ..add(GetDetailedNews(widget.id));
    super.initState();
  }

person Milan Ciganović    schedule 03.11.2019    source источник
comment
Где вы создаете экземпляр объекта NewsBloc? Я не вижу в коде. Убедитесь, что вы не делаете это внутри функции build.   -  person Igor Kharakhordin    schedule 03.11.2019
comment
@IgorKharakhordin Я добавил событие в initState, как в коде выше.   -  person Milan Ciganović    schedule 03.11.2019


Ответы (2)


Я считаю, что проблема в том, что ваше состояние, когда вы нажимаете, чтобы увидеть статью, меняется на DetailedNewsLoaded. Поэтому, когда вы нажимаете назад, BlocBuilder<NewsBloc, NewsState> переходит в состояние else, которое возвращает CircularProgressIndicator.

Насколько я понимаю, в вашем случае вам не нужно состояние DetailedNewsLoaded. Вам просто нужно передать state.node в DetailsScreen в качестве простого аргумента.

person lazos    schedule 03.11.2019
comment
Это две разные конечные точки API. Я использую DetailNewsLoaded для загрузки новостей по идентификатору, который возвращает одну статью. - person Milan Ciganović; 03.11.2019
comment
Хорошо я понял. Итак, если вы print(state); внутри blocBuilder, я думаю, вы увидите состояние DetailedNewsLoaded. Вот тут и возникает проблема. Может быть, вы можете подумать о создании двух разных блоков в вашем случае. Один NewsBloc для вашего списка новостей и еще один DetailsNewBloc для каждой статьи. Затем, когда вы нажимаете кнопку, чтобы увидеть статью, вы можете использовать что-то вроде BlocProvider( builder: (BuildContext context) => DetailsNewBloc()..add(LoadArticle(id)), child: DetailsScreen(), ); - person lazos; 03.11.2019
comment
Возможно, вы уже это проверили, но в любом случае, я думаю, вы снова увидите, как приложение todos использует состояния и события из примеров bloclibrary.dev / # / fluttertodostutorial? id = states Я думаю, это очень близко к тому, чем вы хотите заниматься. Надеюсь, это поможет - person lazos; 03.11.2019

Зачем так много делать, если у вас уже есть виджет героя во Flutter.

  1. Сделай список.
  2. Используйте анимацию героя как для элементов списка, так и для просмотра их подробностей.
  3. При каждом щелчке по элементу списка будет отображаться подробная информация.
  4. Когда пользователь нажимает кнопку «Назад», он / она переходит на позицию, где находился этот конкретный элемент списка.

Так что в основном вам не нужно много.

Я просматривал несколько проектов и нашел это на github: https://github.com/whatsupcoders/Flutter-Hero-Widget

Этот проект рассматривается в этом видео, которое я нашел на YouTube: https://www.youtube.com/watch?v=mgSB5r11_Xw&t=15s

в этом проекте используется виджет Hero, надеюсь, он вам поможет.

person Kalpesh Kundanani    schedule 03.11.2019
comment
Цель - научиться и практиковаться в реализации библиотеки Bloc для более крупных проектов. Таким образом, код будет легче обновить / изменить в будущем. - person Milan Ciganović; 03.11.2019
comment
Ладно, похоже, это тебе не поможет. - person Kalpesh Kundanani; 03.11.2019