带有和不带有 Equatable 的 Flutter bloc 导航

Posted

技术标签:

【中文标题】带有和不带有 Equatable 的 Flutter bloc 导航【英文标题】:Flutter bloc navigation with and without Equatable 【发布时间】:2021-12-14 14:40:31 【问题描述】:

当bloc 状态从Equatable 扩展时,我只能将一个状态导航到另一个屏幕。否则,当状态没有从 Equatable 扩展时,我可以尽可能多地导航到另一个屏幕。

我知道状态和事件应该从 Equatable by Best Practices 扩展,以便能够运行 bloc 测试。也可以使用 Second bloc 覆盖第二个屏幕上的后退按钮行为并执行 Navigator.of(context).push(MaterialPageRoute(builder: (_) return const FirstPage();)),但这似乎是一个错误的举动。

问题:是否可以使用 Equatable 多次导航到另一个屏幕而不覆盖第二个屏幕上的后退按钮功能?

代码:

// main_bloc.dart
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';

// bloc
class MainBloc extends Bloc<MainEvent, MainState> 
  MainBloc() : super(MainInitial()) 
    on<OpenSecondPageEvent>((event, emit) 
      emit(OpeningSecondPageState());
    );
  


// States
abstract class MainState extends Equatable 
  const MainState();

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


class MainInitial extends MainState 

class OpeningSecondPageState extends MainState 

// Events
abstract class MainEvent extends Equatable 
  const MainEvent();

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


class OpenSecondPageEvent extends MainEvent 

用户界面

// main.dart
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

void main() 
  runApp(const MyApp());


class MyApp extends StatelessWidget 
  const MyApp(Key? key) : super(key: key);

  @override
  Widget build(BuildContext context) 
    return MaterialApp(
      home: BlocProvider(

        create: (context) => MainBloc(),
        child: BlocConsumer<MainBloc, MainState>(
          listener: (context, state) 
            if (state is OpeningSecondPageState) 
               Navigator.of(context).push(MaterialPageRoute(builder: (_) 
                return const SecondPage(); // <- Navigating to second screen
              ));
            
          ,
          builder: (context, state) 
            return Scaffold(
              appBar: AppBar(
                title: const Text('Page A'),
              ),
              body: Center(
                child: ElevatedButton(
                  child: const Text('Open Page B'),
                  onPressed: () =>
                      context.read<MainBloc>().add(OpenSecondPageEvent()),
                ),
              ),
            );
          ,
        ),
      ),
    );
  


class SecondPage extends StatelessWidget 
  const SecondPage(Key? key) : super(key: key);

  @override
  Widget build(BuildContext context) 
    return Scaffold(
      appBar: AppBar(
        title: const Text('Page B'),
      ),
      body: Container(),
    );
  


使用 Equatable

没有 Equatable

【问题讨论】:

只是好奇,为什么只为这个基本导航设置Bloc?您的集团中没有其他业务逻辑,那么为什么不直接在onPressed 中进行导航并完成它呢?这会给你你正在寻找的行为。似乎有很多额外的代码没有任何好处。话虽如此,它只工作一次,因为Equatable 在一次推送后并不认为它是一个新状态。第一次推送是MainInitial OpeningSecondPageState,这样就可以了。第二次推送已经是OpeningSecondPageState,所以BlocBuilder不会对它认为相同的状态做出反应。 @Loren.A 回答您的问题,您所看到的只是一个由更复杂的应用程序组成的示例。我删除了与问题无关的所有内容。至于在第二次推送中被认为相同的州,我从我的其他经验中了解到,但无论如何感谢您强调这一点。我想知道有什么方法可以让BlocBuilder 对第二次推送做出反应,或者通过BlocEquatable 听到关于导航主题的其他想法。 【参考方案1】:

作为一种解决方法,可以在OpenSecondPageState() 之后立即发出MainInitial() 状态。

我不认为这是最终解决方案,但它或多或少是整洁的。 在代码中查找// &lt;- Added part

更新集团:

// main_bloc.dart
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';

// bloc
class MainBloc extends Bloc<MainEvent, MainState> 
  MainBloc() : super(MainInitial()) 
    on<OpenSecondPageEvent>((event, emit) 
      emit(OpeningSecondPageState());
      emit(MainInitial()); // <- Added part
    );                    
  


// States
abstract class MainState extends Equatable 
  const MainState();

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


class MainInitial extends MainState 

class OpeningSecondPageState extends MainState 

// Events
abstract class MainEvent extends Equatable 
  const MainEvent();

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


class OpenSecondPageEvent extends MainEvent 

UI部分是一样的

【讨论】:

以上是关于带有和不带有 Equatable 的 Flutter bloc 导航的主要内容,如果未能解决你的问题,请参考以下文章

带有和不带有聚合的 sql 查询

访问控制允许带有和不带有 www 的来源

了解带有和不带有重定向的 JSF 生命周期阶段

生成带有和不带有 HTML 标签的相同文本?

Firestore:获取带有和不带有子集合数据的集合[重复]

带有和不带有数据的 DataGridView 中的按键修饰符