在 Flutter bloc 中管理 onBackPressed 的状态

Posted

技术标签:

【中文标题】在 Flutter bloc 中管理 onBackPressed 的状态【英文标题】:Managing state for onBackPressed in Flutter bloc 【发布时间】:2020-02-28 22:39:37 【问题描述】:

所以我有一个可点击的简单列表并转到 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));
  

块生成器

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();
  

【问题讨论】:

在哪里实例化 NewsBloc 对象?我在代码中看不到。确保您没有在 build 函数中执行此操作。 @IgorKharakhordin 我在 initState 中添加了事件,就像上面的代码一样。 【参考方案1】:

我认为问题在于您按下查看文章时的状态变为DetailedNewsLoaded。因此,当您按下 BlocBuilder&lt;NewsBloc, NewsState&gt; 时,会进入返回 CircularProgressIndicator 的 else 状态。

据我了解,在您的情况下,您不需要 DetailedNewsLoaded 状态。您只需将 state.node 作为简单参数传递给DetailsScreen

【讨论】:

这是两个不同的 API 端点,我使用 DetailNewsLoaded 按 id 加载新闻,返回单个文章。 好的,我明白了。所以如果你print(state);在blocBuilder 里面,我相信你会看到状态是DetailedNewsLoaded。这就是问题出现的地方。也许您可以考虑在您的情况下创建两个不同的集团。一个NewsBloc 用于您的新闻列表,另一个DetailsNewBloc 用于每篇文章。然后,当您按下按钮查看文章时,您可以使用BlocProvider( builder: (BuildContext context) =&gt; DetailsNewBloc()..add(LoadArticle(id)), child: DetailsScreen(), ); 也许你已经检查过了,但无论如何,我认为你可以再次看到 todos 应用程序如何使用示例中的状态和事件bloclibrary.dev/#/fluttertodostutorial?id=states 我认为它非常接近你想要做的事情.希望对你有帮助【参考方案2】:

当你已经在 Flutter 中拥有 hero widget 时,为什么要做这么多。

    列个清单。 对列表项及其详细信息视图使用英雄动画。 只要单击列表项,就会显示详细信息视图。 当用户按下后退按钮时,他/她将来到该特定列表项所在的位置。

所以,基本上你不需要太多。

我正在经历一些项目,我在 github 上找到了这个:https://github.com/whatsupcoders/Flutter-Hero-Widget

这个项目在我在 YouTube 上找到的这个视频中进行了介绍:https://www.youtube.com/watch?v=mgSB5r11_Xw&t=15s

本项目使用 Hero 小部件,希望对您有所帮助。

【讨论】:

目标是学习和实践如何为更大的项目实施 Bloc 库。所以代码在未来更容易升级/更改。 好的,那么这似乎对你没有帮助。

以上是关于在 Flutter bloc 中管理 onBackPressed 的状态的主要内容,如果未能解决你的问题,请参考以下文章

在 Flutter bloc 中管理 onBackPressed 的状态

Flutter - flutter_bloc状态管理

使用 Bloc/Cubit 进行 Flutter 状态管理

Flutter 状态管理之Bloc上

Flutter 状态管理之Bloc上

Flutter 状态管理之Bloc上