首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Flutter:从抽屉到小部件的路由

Flutter:从抽屉到小部件的路由
EN

Stack Overflow用户
提问于 2017-07-25 02:18:50
回答 1查看 1.2K关注 0票数 3

有没有关于如何创建绘图应用程序和重用占据屏幕的小部件的示例?是的,我知道在画廊演示应用程序中有一个例子。然而,这有点厚颜无耻,因为示例实际上不会替换、设置或更改到不同小部件的路由。

我尝试了一个来自抽屉项的onTap事件的小部件的新实例。当从抽屉中选择一个项目并且旧/新路由被弹出/推送时,我尝试在创建这些小部件的新实例时获得重复的全局键错误

代码语言:javascript
复制
ScheduleHomeWidget scheduleWidget = new ScheduleHomeWidget(onSendFeedback: widget.onSendFeedback,);
SpeakerListWidget speakerWidget = new SpeakerListWidget();
var routes = <String, WidgetBuilder> {
  ScheduleHomeWidget.routeName : (BuildContext context) => scheduleWidget,
  SpeakerListWidget.routeName : (BuildContext context) => speakerWidget
};

和我的MaterialApp:

代码语言:javascript
复制
return new MaterialApp(
    title: kAppTitle,
    routes: routes,
    home: scheduleWidget,
);

以及启动新路由的代码:

代码语言:javascript
复制
onTap: () {
    if (routeName != null) {
        Timeline.instantSync('Start Transition', arguments: <String, String>{
            'from': '/',
            'to': routeName
          });
          Navigator.pop(context);
          Navigator.pushNamed(context, routeName);
        }
    }
}

在实例化ScheduleHomeWidgetSpeakerListWidget实例化时,我没有指定键。也就是说,ScheduleHomeWidget使用的AnimatedList确实使用了GlobalKey<AnimatedListState>

我将看到以下异常:

代码语言:javascript
复制
══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
The following assertion was thrown building Flexible(flex: 1):
Multiple widgets used the same GlobalKey.
The key [LabeledGlobalKey<AnimatedListState>#d63d7] was used by multiple widgets. The parents of
those widgets were different widgets that both had the following description:
  Flexible(flex: 1)
A GlobalKey can only be specified on one widget at a time in the widget tree.
When the exception was thrown, this was the stack:
#0      GlobalKey._debugReserveFor.<anonymous closure> (package:flutter/src/widgets/framework.dart:238:9)
#2      GlobalKey._debugReserveFor (package:flutter/src/widgets/framework.dart:219:12)
#3      Element.updateChild.<anonymous closure> (package:flutter/src/widgets/framework.dart:2524:13)
#5      Element.updateChild (package:flutter/src/widgets/framework.dart:2521:12)
#6      ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3403:16)
#7      Element.rebuild (package:flutter/src/widgets/framework.dart:3292:5)
#8      ProxyElement.update (package:flutter/src/widgets/framework.dart:3639:5)
#9      Element.updateChild (package:flutter/src/widgets/framework.dart:2542:15)
#10     RenderObjectElement.updateChildren (package:flutter/src/widgets/framework.dart:4066:32)
#11     MultiChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:4448:17)
#12     Element.updateChild (package:flutter/src/widgets/framework.dart:2542:15)
#13     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3403:16)
#14     Element.rebuild (package:flutter/src/widgets/framework.dart:3292:5)
#15     ProxyElement.update (package:flutter/src/widgets/framework.dart:3639:5)
#16     Element.updateChild (package:flutter/src/widgets/framework.dart:2542:15)
#17     RenderObjectElement.updateChildren (package:flutter/src/widgets/framework.dart:4066:32)
#18     MultiChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:4448:17)
#19     Element.updateChild (package:flutter/src/widgets/framework.dart:2542:15)
#20     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3403:16)
#21     Element.rebuild (package:flutter/src/widgets/framework.dart:3292:5)
#22     ProxyElement.update (package:flutter/src/widgets/framework.dart:3639:5)
#23     Element.updateChild (package:flutter/src/widgets/framework.dart:2542:15)
#24     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3403:16)
#25     Element.rebuild (package:flutter/src/widgets/framework.dart:3292:5)
#26     StatefulElement.update (package:flutter/src/widgets/framework.dart:3528:5)
#27     Element.updateChild (package:flutter/src/widgets/framework.dart:2542:15)
#28     SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:4340:14)
#29     Element.updateChild (package:flutter/src/widgets/framework.dart:2542:15)
#30     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3403:16)
#31     Element.rebuild (package:flutter/src/widgets/framework.dart:3292:5)
#32     StatelessElement.update (package:flutter/src/widgets/framework.dart:3453:5)
#33     Element.updateChild (package:flutter/src/widgets/framework.dart:2542:15)
#34     SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:4340:14)
#35     Element.updateChild (package:flutter/src/widgets/framework.dart:2542:15)
#36     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3403:16)
#37     Element.rebuild (package:flutter/src/widgets/framework.dart:3292:5)
#38     StatefulElement.update (package:flutter/src/widgets/framework.dart:3528:5)
#39     Element.updateChild (package:flutter/src/widgets/framework.dart:2542:15)
#40     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3403:16)
#41     Element.rebuild (package:flutter/src/widgets/framework.dart:3292:5)
#42     StatefulElement.update (package:flutter/src/widgets/framework.dart:3528:5)
#43     Element.updateChild (package:flutter/src/widgets/framework.dart:2542:15)
#44     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3403:16)
#45     Element.rebuild (package:flutter/src/widgets/framework.dart:3292:5)
#46     ProxyElement.update (package:flutter/src/widgets/framework.dart:3639:5)
#47     Element.updateChild (package:flutter/src/widgets/framework.dart:2542:15)
#48     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3403:16)
#49     Element.rebuild (package:flutter/src/widgets/framework.dart:3292:5)
#50     ProxyElement.update (package:flutter/src/widgets/framework.dart:3639:5)
#51     Element.updateChild (package:flutter/src/widgets/framework.dart:2542:15)
#52     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3403:16)
#53     Element.rebuild (package:flutter/src/widgets/framework.dart:3292:5)
#54     StatefulElement.update (package:flutter/src/widgets/framework.dart:3528:5)
#55     Element.updateChild (package:flutter/src/widgets/framework.dart:2542:15)
#56     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3403:16)
#57     Element.rebuild (package:flutter/src/widgets/framework.dart:3292:5)
#58     BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2142:33)
#59     BindingBase&SchedulerBinding&GestureBinding&ServicesBinding&RendererBinding&WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:503:20)
#60     BindingBase&SchedulerBinding&GestureBinding&ServicesBinding&RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:189:5)
#61     BindingBase&SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:688:15)
#62     BindingBase&SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:636:9)
#63     BindingBase&SchedulerBinding&GestureBinding&ServicesBinding&RendererBinding.scheduleWarmUpFrame.<anonymous closure> (package:flutter/src/rendering/binding.dart:275:20)
#65     _Timer._runTimers (dart:isolate-patch/timer_impl.dart:366)
#66     _Timer._handleMessage (dart:isolate-patch/timer_impl.dart:394)
#67     _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:151)
(elided 3 frames from class _AssertionError and package dart:async-patch)
════════════════════════════════════════════════════════════════════════════════════════════════════
Reloaded 9 of 459 libraries in 2,143ms.
Another exception was thrown: 'package:flutter/src/widgets/framework.dart': Failed assertion: line 3727 pos 14: '_dependents.isEmpty': is not true.
Another exception was thrown: 'package:flutter/src/widgets/framework.dart': Failed assertion: line 1662 pos 12: '_elements.contains(element)': is not true.`

这个错误看起来像是Flutter多次尝试通过小部件的ID向树中添加小部件。我并不是真的想这么做。只是希望有两个窗口小部件,可以采取的主要焦点的屏幕。不一定要在用户每次从侧边栏选择时都创建一个新的。

EN

回答 1

Stack Overflow用户

发布于 2021-11-18 07:25:52

您在这里可以做的是在home上添加一个导航器。使用此设置,您可以使用导航键管理导航。

代码语言:javascript
复制
@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: Text(widget.title),
    ),
    drawer: Drawer(
      child: ListView(
        children: _drawer(),
      ),
    ),
    body: Navigator(
      key: _navigatorKey, // use a Navigator key so the app won't be confused when managing routes
      initialRoute: Nemo.pageA, // Set default page
      ...
    ),
  );
}

Navigator返回所选选项卡的小部件构建器。

代码语言:javascript
复制
Navigator(
  key: _navigatorKey, // use a Navigator key so the app won't be confused when managing routes
  initialRoute: Nemo.pageA, // Set default page
  onGenerateRoute: (RouteSettings settings) {
    WidgetBuilder builder;
    _currentPage = settings.name;
    // Depending on the route name pushed
    // set the Widget builder to be returned by the Navigator
    // if pushed route is non-existent, return a 404 page
    switch (settings.name) {
      case Nemo.pageA:
        builder = (BuildContext context) => const Center(child: Text('Page A'));
        break;
      case Nemo.pageB:
        builder = (BuildContext context) => const Center(child: Text('Page B'));
        break;
      case Nemo.pageC:
        builder = (BuildContext context) => const Center(child: Text('Page C'));
        break;
      default:
        builder = (BuildContext context) => const Center(child: Text('404'));
    }
    return MaterialPageRoute(
      builder: builder,
      settings: settings,
    );
  },
),

在你的抽屉上,当标签被点击时,你可以推送路线。检查点击的选项卡是否是屏幕上显示的当前页面,以便导航器不会再次推送相同的页面。

代码语言:javascript
复制
List<Widget> _drawer() {
  return <Widget>[
    ListTile(
      title: const Text('Page A'),
      onTap: () {
        Navigator.pop(context);
        if (_currentPage != Nemo.pageA) {
          _navigatorKey.currentState!
              .pushNamedAndRemoveUntil(Nemo.pageA, (Route route) => false);
        }
      },
    ),
    ...
  ];
}

完整示例

代码语言:javascript
复制
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class Nemo {
  static const String pageA = '/pageA';
  static const String pageB = '/pageB';
  static const String pageC = '/pageC';
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final _navigatorKey = GlobalKey<NavigatorState>();
  String? _currentPage;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      drawer: Drawer(
        child: ListView(
          children: _drawer(),
        ),
      ),
      body: Navigator(
        key:
            _navigatorKey, // use a Navigator key so the app won't be confused when managing routes
        initialRoute: Nemo.pageA, // Set default page
        onGenerateRoute: (RouteSettings settings) {
          WidgetBuilder builder;
          _currentPage = settings.name;
          // Depending on the route name pushed
          // set the Widget builder to be returned by the Navigator
          // if pushed route is non-existent, return a 404 page
          switch (settings.name) {
            case Nemo.pageA:
              builder =
                  (BuildContext context) => const Center(child: Text('Page A'));
              break;
            case Nemo.pageB:
              builder =
                  (BuildContext context) => const Center(child: Text('Page B'));
              break;
            case Nemo.pageC:
              builder =
                  (BuildContext context) => const Center(child: Text('Page C'));
              break;
            default:
              builder =
                  (BuildContext context) => const Center(child: Text('404'));
          }
          return MaterialPageRoute(
            builder: builder,
            settings: settings,
          );
        },
      ),
    );
  }

  List<Widget> _drawer() {
    return <Widget>[
      ListTile(
        title: const Text('Page A'),
        onTap: () {
          Navigator.pop(context);
          if (_currentPage != Nemo.pageA) {
            _navigatorKey.currentState!
                .pushNamedAndRemoveUntil(Nemo.pageA, (Route route) => false);
          }
        },
      ),
      ListTile(
        title: const Text('Page B'),
        onTap: () {
          Navigator.pop(context);
          if (_currentPage != Nemo.pageB) {
            _navigatorKey.currentState!
                .pushNamedAndRemoveUntil(Nemo.pageB, (Route route) => false);
          }
        },
      ),
      ListTile(
        title: const Text('Page C'),
        onTap: () {
          Navigator.pop(context);
          if (_currentPage != Nemo.pageC) {
            _navigatorKey.currentState!
                .pushNamedAndRemoveUntil(Nemo.pageC, (Route route) => false);
          }
        },
      ),
    ];
  }
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/45287429

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档