【问题标题】:How to dynamically change the App Title in Flutter Web?如何在 Flutter Web 中动态更改 App Title?
【发布时间】:2020-06-12 20:25:12
【问题描述】:

网络应用通常会在标签的标题中反映当前显示的内容。

title parameter 提供给MaterialAppWidgetsApp 意味着我无法在不重建整个树的情况下更改它,即在我返回@ 的顶层调用setState 987654328@.

MaterialApp(
  title: 'Web app title',
  ...,
)

我希望能够在任何时间从应用中的anywhere更改应用标题。我该怎么做?

【问题讨论】:

    标签: flutter dart flutter-web


    【解决方案1】:

    Flutter 中的动态应用标题

    应用标题可以使用SystemChrome.setApplicationSwitcherDescription动态在所有平台上更改:

    @override
    Widget build(BuildContext context) {
        SystemChrome.setApplicationSwitcherDescription(ApplicationSwitcherDescription(
          label: 'Dynamic web app title',
          primaryColor: Theme.of(context).primaryColor.value,
        ));
    
    
      return Container(...);
    }
    

    SystemChromeimport 'package:flutter/services.dart'; 一起可用,并且您想在 build 方法中调用 setApplicationSwitcherDescription

    Title 也是这样做的(参见source code),这是WidgetsAppMaterialApp 等使用的小部件。

    因此,您也可以使用Title 小部件而不是自己访问SystemChrome

    @override
    Widget build(Context context) {
      return Title(
        label: 'Dynamic app title',
        primaryColor: Theme.of(context).primaryColor,
        child: ..,
      );
    }
    

    label

    label 参数非常简单:它精确映射到 title 在您的 MaterialApp 中的内容,并且只是一个 String

    primaryColor

    primaryColor 将确定系统可能在应用程序切换器中使用的颜色,例如Android 上最近使用的标题栏颜色。
    这是Colorint,而不是,这就是为什么您需要调用Color.value 将您的原色转换为整数。

    干扰其他Titles

    您可能会问自己,在设置MaterialApp 上的title 属性时调用setApplicationSwitcherDescription 或插入Title 小部件是否会导致任何问题。
    答案是:,因为树中最深处的小部件将设置标题。从本质上讲,即使整个应用程序重新构建,您的 setApplicationSwitcherDescription 也会在 MaterialApp 之后被调用,假设您在孩子中调用它,因此您将覆盖 MaterialApp 标题。

    【讨论】:

    • @easeccy 您的编辑正在discissed on meta
    • 使用Title 小部件,使用Navigator.pop(context); 从另一个页面返回时如何恢复标题?或者如何检测onResume 事件以便我可以调用SystemChrome.setApplicationSwitcherDescription()?我对这种简单需求的复杂性感到困惑。
    【解决方案2】:

    这已经晚了将近 2 年,但我为此找到了不错的解决方案。没那么简单,但是很好用。

    ma​​in.dart

    MaterialApp内,添加navigatorObservers

    MaterialApp(
      initialRoute: "/welcome",
      routes: <String, WidgetBuilder>{
        '/welcome':  (BuildContext context) => WelcomeScreen(),
        '/login':    (BuildContext context) => LoginScreen(),
        '/register': (BuildContext context) => RegisterScreen(),
      },
      // other codes ...
      navigatorObservers: [MyRouteObserver()],
      // other codes ...
    );
    

    在最底部添加:

    class MyRouteObserver extends RouteObserver<PageRoute<dynamic>> {
      void _setTitle(String what, PageRoute<dynamic> routeFrom, PageRoute<dynamic> routeTo) {
        final oldScreenName = routeFrom.settings.name;
        final newScreenName = routeTo.settings.name;
        log("route changed: $what ($oldScreenName -> $newScreenName)"); // it's just route activity log, don't forget to import 'dart:developer';
        final uri = Uri.parse(newScreenName ?? "");
        final routeName = uri.pathSegments.isNotEmpty ? uri.pathSegments.first : "";
        switch ("/$routeName") {
          case "/welcome"  : return setTitle("Welcome");
          case "/login"    : return setTitle("Login");
          case "/register" : return setTitle("Sign Up");
          // etc ...
        }
        setTitle("Not Found");
      }
    
      @override
      void didPush(Route<dynamic> route, Route<dynamic>? previousRoute) {
        super.didPush(route, previousRoute);
        if (route is PageRoute && previousRoute is PageRoute) _setTitle("push", previousRoute, route);
      }
    
      @override
      void didReplace({Route<dynamic>? newRoute, Route<dynamic>? oldRoute}) {
        super.didReplace(newRoute: newRoute, oldRoute: oldRoute);
        if (newRoute is PageRoute && oldRoute is PageRoute) _setTitle("replace", oldRoute, newRoute);
      }
    
      @override
      void didPop(Route<dynamic> route, Route<dynamic>? previousRoute) {
        super.didPop(route, previousRoute);
        if (route is PageRoute && previousRoute is PageRoute) _setTitle("pop", route, previousRoute);
      }
    }
    

    helpers.dart

    void setTitle([String? title]) async {
      Future.microtask(() {
        SystemChrome.setApplicationSwitcherDescription(ApplicationSwitcherDescription(
          label: "Your APP | ${title ?? 'Your Tagline'}",
          primaryColor: Colors.blue.value, // your app primary color
        ));
      });
    }
    

    最后,如果您想在特定页面中单独覆盖标题,请执行以下操作:

    @override
    void initState() {
      super.initState();
      WidgetsBinding.instance?.addPostFrameCallback((_) {
        setTitle("Custom Page Title");
      });
    }
    

    【讨论】:

      猜你喜欢
      • 2021-05-31
      • 1970-01-01
      • 2021-04-06
      • 1970-01-01
      • 2019-09-29
      • 2014-09-07
      • 2020-12-08
      • 2020-04-11
      • 1970-01-01
      相关资源
      最近更新 更多