簡體   English   中英

如何根據所選的 GoRouter 路由更改應用欄標題?

[英]How to change the app bar title depending on the selected GoRouter route?

我想使用固定的ScaffoldAppBar實現基於 GoRouter 的導航,但根據所選路線動態更改AppBar的標題。

我正在使用 GoRouter 的ShellRoute來固定ScaffoldAppBar ,並嘗試使用 riverpod Provider更改標題:

final titleProvider = StateProvider((ref) => 'Title');

ShellRoute(
   builder: (BuildContext context, GoRouterState state, Widget child) {
       return Scaffold(
         body: child,
         appBar: CustomAppBar()
       );
   },
   routes: [
       GoRoute(
          path: DashboardScreenWeb.routeLocation,
          name: DashboardScreenWeb.routeName,
          builder: (context, state) {
             ref.read(titleProvider.state).state = DashboardScreenWeb.title;
             return const DashboardScreenWeb();
          },
       ),
       GoRoute(
          path: BusinessDataScreen.routeLocation,
          name: BusinessDataScreen.routeName,
          builder: (context, state) {
            ref.read(titleProvider.state).state = BusinessDataScreen.title;
            return const BusinessDataScreen();
          },
        ),
....

我的CustomAppBar小部件像這樣使用此提供程序:

class CustomAppBar extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    var title = ref.watch(titleProvider);
    return new AppBar(
      title: Text(title!)
    );
  }
}

但是,我遇到了很多異常,很可能是因為我在錯誤的時間更改了提供商的 state。 我該怎么辦?

======== Exception caught by widgets library =======================================================
The following StateNotifierListenerError was thrown building Builder(dirty):
At least listener of the StateNotifier Instance of 'StateController<String>' threw an exception
when the notifier tried to update its state.

The exceptions thrown are:

setState() or markNeedsBuild() called during build.
This UncontrolledProviderScope widget cannot be marked as needing to build because the framework is already in the process of building widgets. A widget can be marked as needing to be built during the build phase only if one of its ancestors is currently building. This exception is allowed because the framework builds parent widgets before children, which means a dirty descendant will always be built. Otherwise, the framework might not visit this widget during this build phase.
The widget on which setState() or markNeedsBuild() was called was:
  UncontrolledProviderScope
The widget which was currently being built when the offending call was made was:

使用 state 屬性state.location並將title傳遞給AppBar

Go 路由器


final _rootNavigatorKey = GlobalKey<NavigatorState>();
final _shellNavigatorKey = GlobalKey<NavigatorState>();

final router = GoRouter(
  initialLocation: '/',
  navigatorKey: _rootNavigatorKey,
  routes: [
    ShellRoute(
      navigatorKey: _shellNavigatorKey,
      pageBuilder: (context, state, child) {
        String title;
        switch (state.location) {              // 👈 Using state.location to set title
          case '/':
            title = "Initial Screen";
            break;
          case '/home':
            title = "Home Screen";
            break;
          default:
            title = "Default Screen";
        }
        return NoTransitionPage(
            child: ScaffoldAppAndBottomBar(
          appTitle: title,                    // 👈 pass title here
          child: child,
        ));
      },
      routes: [
        GoRoute(
          parentNavigatorKey: _shellNavigatorKey,
          path: '/home',
          name: 'Home Title',
          pageBuilder: (context, state) {
            return const NoTransitionPage(
              child: Scaffold(
                body: Center(
                  child: Text("Home"),
                ),
              ),
            );
          },
        ),
        GoRoute(
          path: '/',
          name: 'App Title',
          parentNavigatorKey: _shellNavigatorKey,
          pageBuilder: (context, state) {
            return const NoTransitionPage(
              child: Scaffold(
                body: Center(child: Text("Initial")),
              ),
            );
          },
        ),
      ],
    ),
  ],
);

自定義應用欄


class CustomAppBar extends StatelessWidget {
  Widget child;
  String? appTitle;
  CustomAppBar(
      {super.key, required this.child, required this.appTitle});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        centerTitle: true,
        title: Text(appTitle ?? "Default"),
      ),
      body: SafeArea(child: child),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          context.go('/home');
        },
        child: const Icon(Icons.home),
      ),
    );
  }
}

Output:

在此處輸入圖像描述

在此處輸入圖像描述

你應該這樣定義你的 titleProvider:

 final titleProvider = Provider<String>((ref) => 'Title');

並更新提供者:

 GoRoute( path: BusinessDataScreen.routeLocation, name: BusinessDataScreen.routeName, builder: (context, state) { return ProviderScope( overrides: [ titleProvider.overrideWithValue('youTitleHere') ] child: const BusinessDataScreen(), ); }, ),

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM