首页 > 解决方案 > 在命名路由器中传递参数的最佳方法

问题描述

我有两个命名的路由器小部件,我应该如何使用 bloc 模式将参数从一个传递到另一个?

// main.dart

void main() => runApp(App());

class App extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MultiBlocProvider(
      providers: [
        BlocProvider<OneBloc>(create: (BuildContext context) => OneBloc()),
        BlocProvider<TwoBloc>(
            create: (BuildContext context) => TwoBloc())
      ],
      child: MaterialApp(
        title: 'testApp',
        initialRoute: '/one',
        routes: {
          '/one': (context) => One(),
          '/two': (context) => Two()
        },
      ),
    );
  }
}

// one_bloc.dart

class OneBloc extends Bloc<OneEvent, OneState> {
  OneBloc() : super(OneInitial());

  @override
  Stream<OneState> mapEventToState(
    OneEvent event,
  ) async* {
    if (event is PassParameter) {
      yield NavigateToTwo('parameter from One');
    }
  }
}

// one_state.dart

@immutable
abstract class OneState extends Equatable {
  const OneState();

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

class NavigateToTwo extends OneState {
  final String parameter;

  NavigateToTwo(this.parameter);
}

// One.dart -- part of UI code

  @override
  Widget build(BuildContext context) {
    return BlocConsumer<OneBloc, OneState>(listener: (context, state) {
      if (state is NavigateToTwo) {
        Navigator.pushNamed(context, '/two'); // how to pass the state.parameter to TwoBloc
      }
    },
    // other code.

更新

在查看官网的 todo 示例后,它应该使用 TwoBloc 中的 StreamSubscription 来监听 OneBloc NavigateToTwo 状态以获取参数。

标签: flutterflutter-bloc

解决方案


首先,您创建了一个类变量来接收要在类之间传递的参数。

Class One {
  final a;
  One({this.a});
...
}

您可以通过导航器将参数作为这样的参数传递

Map<String, dynamic> myArguments = {"argumentKey": value};
Navigator.pushNamed(context, '/two', arguments: myArgument);

然后你可以像这样在 MaterialApp 的 onGenerateRoute() 中访问这个参数

MaterialApp(
  onGenerateRoute: (settings) {
  final args = settings.arguments;
  if (settings.name == '/one') {
    final argumentForPageOne = args["argumentForPageOne"];
  }
  if (settings.name == '/two') {
    final argumentForPageTwo = args["argumentForPageTwo"];
  }
  Map<String, Widget> widgets = {
    '/one': One(a: argumentForPageOne),
    '/two': Two(b: argumentForPageTwo)
 }
    return MaterialPageRoute(
      builder: (context) {
        return widgets[settings.name];
        },
      );
    }
  },
);

对于具有多个屏幕的大型项目,您必须创建自定义路由器类以进行导航。

例子:

class RouterService {
  final GlobalKey<NavigatorState> navigationKey = GlobalKey<NavigatorState>();
  Route<dynamic> generateRoutes(RouteSettings settings) {
  final List<String> validRoutes = [
    '/home',
    '/introduction',
  ];
  PageRouteBuilder<dynamic> customRoutes(
    String route, Map<String, dynamic> args) {
    String message;
    bool showTutorial;
    if (args != null) {
      if (args.containsKey('message')) {
       message = args['message'];
      }
      if (args.containsKey('showTutorial')) {
        showTutorial = args['showTutorial'];
      } 
    }
    Map<String, Widget> screens = {
      '/home': HomeScreen(
        message: message,
        showTutorial: showTutorial,
      ),
      '/introduction': IntroductionScreen(),
      ...
    };

    return PageRouteBuilder(
        pageBuilder: (_, __, ___) => screens[route],
        transitionsBuilder: (_, anim, __, child) => FadeTransition(
            opacity: anim,
            child: child,
          ),
        transitionDuration: Duration(milliseconds: 250));
    }
  }
  if (validRoutes.contains(settings.name)) {
    return customRoutes(settings.name, settings.arguments);
  } else {
    return MaterialPageRoute(builder: (_) {
      return NotFoundScreen();
    });
  }
}

然后在 MaterialApp 中使用这个自定义路由器

MaterialApp(
  ...,
  onGenerateRoute: RouterService().generateRoutes,
)

推荐阅读