使用一个集团,一种分页形式的状态?

Using one bloc, one state in page-splitted form?

我有一个 单一表单 ,它根据用户体验和 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)

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

我该怎么做?

NOTE

  • Each form is a page, not a tabbar or pageview.
  • I want only 1 bloc and 1 state to be shared across the page, not 1 bloc per page.
  • I want this behavior simply because I'm actually avoid passing data from the constructor.
  • Already tried BlocProvider.of<MyBloc>(context).state but it is not giving me access to the object.

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

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];
}