首页 > 解决方案 > 以分页形式使用一个集团,一种状态?

问题描述

我有一个单一的表格,根据 UX 和 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而不将我的树包装在 a 内,或者因为没有像在需要状态更改时重建小部件这样的事情。RaisedButtonblocbuilder, bloclistenerblocconsumer

我怎样才能做到这一点?

笔记

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

IDE 自动补全截图

标签: flutterblocflutter-bloc

解决方案


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

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

推荐阅读