【问题标题】:Using one bloc, one state in page-splitted form?使用一个集团,一种分页形式的状态?
【发布时间】:2025-12-22 07:10:07
【问题描述】:

我有一个单一表单,根据用户体验和 UI 设计要求,它被分成 3 页。结构如下:

MyApp
  |
  |- BlocProvider.of<MyBloc>(context)
      |- PageA
      |    |- FormA
      |         |- InputA
      |         |- InputB
      |         |- InputC
      |         |- RaisedButton (Next button)
      |
      |- PageB
      |    |- FormA
      |         |- InputD
      |         |- InputE
      |         |- InputF
      |         |- RaisedButton (Back button)
      |         |- RaisedButton (Next button)
      |
      |- PageC
      |    |- FormA
      |         |- InputG
      |         |- InputH
      |         |- InputI
      |         |- RaisedButton (Back button)
      |         |- RaisedButton (Submit button)

我想传递相同的状态,并更新 onPressed 的状态数据 RaisedButton 按钮 不将我的树 包裹在 blocbuilder, bloclistenerblocconsumer 内,因为没有这样的东西比如在需要状态更改时重建小部件。

我该怎么做?

注意

  • 每个表单都是一个页面,而不是标签栏或页面浏览量。
  • 我希望整个页面只共享 1 个块和 1 个状态,而不是每页共享 1 个块。
  • 我想要这种行为仅仅是因为我实际上是在避免从构造函数传递数据。
  • 已经尝试过BlocProvider.of&lt;MyBloc&gt;(context).state,但它不允许我访问该对象。

【问题讨论】:

    标签: flutter bloc flutter-bloc


    【解决方案1】:

    我做了一个非常简单的例子,希望对你有帮助。

    import 'package:equatable/equatable.dart';
    import 'package:flutter/material.dart';
    import 'package:flutter_bloc/flutter_bloc.dart';
    
    void main() => runApp(MyApp());
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return BlocProvider(
          create: (_) => MyForm(),
          child: MaterialApp(
            title: 'Flutter Demo',
            home: HomePage(),
          ),
        );
      }
    }
    
    class HomePage extends StatelessWidget {
      Widget build(BuildContext context) {
        return Scaffold(
          body: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: [
              BlocBuilder<MyForm, MyFromState>(
                builder: (_, state) {
                  return Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    crossAxisAlignment: CrossAxisAlignment.center,
                    children: [
                      Text('inputA: ${state.inputA}'),
                      Text('inputB: ${state.inputB}'),
                      Text('inputC: ${state.inputC}'),
                      Text('inputD: ${state.inputD}'),
                      Text('inputE: ${state.inputE}'),
                      Text('inputF: ${state.inputF}'),
                    ],
                  );
                },
              ),
              Center(
                child: RaisedButton(
                  onPressed: () {
                    Navigator.push(
                      context,
                      MaterialPageRoute(builder: (context) => FirstPage()),
                    );
                  },
                  child: Text('start'),
                ),
              ),
            ],
          ),
        );
      }
    }
    
    class FirstPage extends StatelessWidget {
      Widget build(BuildContext context) {
        var bloc = BlocProvider.of<MyForm>(context);
        return Scaffold(
          body: Center(
            child: RaisedButton(
              onPressed: () {
                bloc.add(FirstPageSubmitEvent(
                  inputA: 'text1',
                  inputB: 'text2',
                ));
                Navigator.push(
                  context,
                  MaterialPageRoute(builder: (context) => SecondPage()),
                );
              },
              child: Text('page 2'),
            ),
          ),
        );
      }
    }
    
    class SecondPage extends StatelessWidget {
      Widget build(BuildContext context) {
        var bloc = BlocProvider.of<MyForm>(context);
        return Scaffold(
          body: Center(
            child: RaisedButton(
              onPressed: () {
                bloc.add(SecondPageSubmitEvent(
                  inputC: 'text3',
                  inputD: 'text4',
                ));
                Navigator.push(
                  context,
                  MaterialPageRoute(builder: (context) => ThirdPage()),
                );
              },
              child: Text('page 3'),
            ),
          ),
        );
      }
    }
    
    class ThirdPage extends StatelessWidget {
      Widget build(BuildContext context) {
        var bloc = BlocProvider.of<MyForm>(context);
        return Scaffold(
          body: Center(
            child: RaisedButton(
              onPressed: () {
                bloc.add(ThirdPageSubmitEvent(
                  inputE: 'text5',
                  inputF: 'text6',
                ));
                Navigator.pushAndRemoveUntil(
                  context,
                  MaterialPageRoute(builder: (context) => HomePage()),
                  (r) => r == null,
                );
              },
              child: Text('page 3'),
            ),
          ),
        );
      }
    }
    
    class MyForm extends Bloc<MyFormEvent, MyFromState> {
      MyForm() : super(MyFromState.empty);
    
      @override
      Stream<MyFromState> mapEventToState(MyFormEvent event) async* {
        if (event is FirstPageSubmitEvent) {
          yield (state.copyWith(
            inputA: event.inputA,
            inputB: event.inputB,
          ));
        } else if (event is SecondPageSubmitEvent) {
          yield (state.copyWith(
            inputC: event.inputC,
            inputD: event.inputD,
          ));
        } else if (event is ThirdPageSubmitEvent) {
          yield (state.copyWith(
            inputE: event.inputE,
            inputF: event.inputF,
          ));
        }
      }
    }
    
    abstract class MyFormEvent extends Equatable {}
    
    class FirstPageSubmitEvent extends MyFormEvent {
      FirstPageSubmitEvent({this.inputA, this.inputB});
    
      final String inputA;
      final String inputB;
    
      @override
      List<Object> get props => [inputA, inputB];
    }
    
    class SecondPageSubmitEvent extends MyFormEvent {
      SecondPageSubmitEvent({this.inputC, this.inputD});
    
      final String inputC;
      final String inputD;
    
      @override
      List<Object> get props => [inputC, inputD];
    }
    
    class ThirdPageSubmitEvent extends MyFormEvent {
      ThirdPageSubmitEvent({this.inputE, this.inputF});
    
      final String inputE;
      final String inputF;
    
      @override
      List<Object> get props => [inputE, inputF];
    }
    
    class MyFromState extends Equatable {
      final String inputA;
      final String inputB;
      final String inputC;
      final String inputD;
      final String inputE;
      final String inputF;
    
      const MyFromState({
        this.inputA,
        this.inputB,
        this.inputC,
        this.inputD,
        this.inputE,
        this.inputF,
      });
    
      static const empty = MyFromState(
        inputA: '',
        inputB: '',
        inputC: '',
        inputD: '',
        inputE: '',
        inputF: '',
      );
    
      MyFromState copyWith({
        String inputA,
        String inputB,
        String inputC,
        String inputD,
        String inputE,
        String inputF,
      }) {
        return MyFromState(
          inputA: inputA ?? this.inputA,
          inputB: inputB ?? this.inputB,
          inputC: inputC ?? this.inputC,
          inputD: inputD ?? this.inputD,
          inputE: inputE ?? this.inputE,
          inputF: inputF ?? this.inputF,
        );
      }
    
      @override
      List<Object> get props => [inputA, inputB, inputC, inputD, inputE, inputF];
    }
    

    【讨论】:

    • 酷..!最后,一个非常好的实现示例。
    • 嘿,我在尝试访问state.copyWith 时遇到了这个错误。 _CompileTimeError (Unimplemented handling of missing static target)
    • 我和你做的一模一样
    • 没关系,停止并重新运行应用程序后它现在可以工作
    最近更新 更多