gpt4 book ai didi

dart - 抽屉导航不适用于屏幕内的屏幕

转载 作者:IT王子 更新时间:2023-10-29 07:23:06 25 4
gpt4 key购买 nike

我想在所有屏幕上保留 Navigation Drawer。对此有很多问题,但我的问题与例如Persisting AppBar Drawer across all Pages Flutter

我有抽屉导航,其中包含名为 A、B 和 C 的项目列表。在抽屉导航中单击 A 时,屏幕 A 打开,B 和 C 分别打开相同的内容。现在 C 屏幕有一个按钮,单击该按钮按钮 我要去屏幕 D,现在虽然屏幕 D 显示抽屉导航图标,但抽屉永远不会打开。我尝试在调用抽屉的方法中打印一条语句,打印语句确实打印但抽屉永远不会打开。以下是我的代码

我有一个基类,它的抽屉如下

 class BaseScreen extends StatefulWidget {
final List<Menu> menuList;
final String userType;
final String userId;

const BaseScreen({Key key, this.menuList, this.userType, this.userId})
: super(key: key);

@override
BaseScreenState createState() {
return new BaseScreenState();
}
}

class BaseScreenState extends State<BaseScreen> {
String screenNameSelected = "A";

@override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: <Widget>[
_getDrawerItemWidget(screenNameSelected),

],
),
drawer: SizedBox(
width: 100,
child: Drawer(
child: ListView.separated(
separatorBuilder: (context, index) => Material(
elevation: 2,
shadowColor: shadow,
child: Divider(
color: white,
),
),
itemBuilder: (BuildContext context, int index) {
return ListTile(
onTap: () {
openScreen(
widget.menuList[index].title,
widget.userId,
MenuList.returnLoginType(widget.userType).toString(),
context);
Navigator.pop(context);
},
title: Padding(
padding: const EdgeInsets.only(top: 8),
child: Image.asset(
widget.menuList[index].image,
width: 35,
height: 35,
),
),

);
},
itemCount: widget.menuList?.length ?? 0,
shrinkWrap: true,
physics: BouncingScrollPhysics(),
),
),
),
);
}

_getDrawerItemWidget(String selectedScreenName) {
switch (selectedScreenName) {
case A:
return A();
case B:
return B();
case C:
return C();

default:
return Container();
}
}

void openScreen(String screenName, String userId, String loginType,
BuildContext context) {
if (screenName.toLowerCase() == "A".toLowerCase()) {
setState(() {
screenNameSelected = "A";
});
} else if (screenName.toLowerCase() == "B".toLowerCase()) {
setState(() {
screenNameSelected = "B";
});
} else if (screenName.toLowerCase() == "C".toLowerCase()) {
setState(() {
screenNameSelected = "C";
});
}

}

}

我已经为应用栏创建了一个自定义类,因为我的应用栏是高度定制的

class CustomAppBar extends StatelessWidget {
final String subTitleText;
final String subTitleImage;

const CustomAppBar(
{Key key, @required this.subTitleText, @required this.subTitleImage})
: super(key: key);

@override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
SafeArea(
child: Column(
children: <Widget>[
Builder(builder: (context) => customAppBar(context)),
SizedBox(
height: 5.0,
),
subTitleRow(
subTitleText,
subTitleImage,
)
],
),
),

],
);
}
}

Widget subTitleRow(String subtitleText, String subtitleImage) {
.........
}


Widget customAppBar(BuildContext context) {
return Material(
elevation: 5.0,
shadowColor: shadow,
child: SafeArea(
child: Stack(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Image.asset(
"images/toolbar_logo.webp",
width: 80,
height: 50,
),
],
),
IconButton(
icon: Image.asset("images/menu.webp"),
onPressed: () {
Scaffold.of(context).openDrawer();
},
iconSize: 20,
),
],
),
),
);
}

现在我的 A、B 和 C 类没有脚手架,但我为 D 类提供了脚手架,我认为这是导致问题的原因。不为 D 类提供脚手架不会提供正确的布局

A、B、C类代码如下

class A extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ShortBioProvider(
child: Column(
children: <Widget>[
CustomAppBar(
subTitleImage: "images/settings.webp",
subTitleText: SETTINGS.toUpperCase(),
),
SizedBox(
height: 20,
),
SettingsList(),
],
),

);
}
}

B 和 C 与 A 非常相似。

现在是D类代码

class D extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(body: Column(children: <Widget>[
CustomAppBar(
subTitleImage: "images/settings.webp",
subTitleText: D.toUpperCase(),
),
SizedBox(
height: 20,
),
........
],),);
}
}

我对上面的类进行了很多编辑,所以这里或那里可能缺少括号或分号

最佳答案

啊,现在您已经添加了您的代码,这很有意义。

发生的事情是,在 D 的情况下,您有两个不同的脚手架:

BaseScreenState
--> Scaffold 1
--> drawer
body
--> stack
--> D
--> Scaffold 2
-->CustomAppBar ....

当您执行 Scaffold.of(context) 时,它会向上查找树以找到最近的脚手架,在本例中恰好是没有抽屉的脚手架 2。你的 D 类中的脚手架似乎没有做任何事情,所以删除它应该可以解决你的问题。

然而

您的代码中存在一些更严重的问题。您几乎不应该使用堆栈在页面之间切换。一方面,flutter 无法以这种方式缓存小部件,但它也消除了屏幕转换等内容。

您应该做的是为应用中的每个页面创建一个包含脚手架、抽屉、应用栏等的页面,然后使用导航器在这些页面之间切换。 (请注意,仅仅因为您为每个页面制作了一个小部件,并不意味着组件不能共享)。

一个在flutter中有意义的架构如下:

  • 顶级有状态小部件(有状态更适合热重载,无状态小部件可能会导致问题),类似于 MyApp(但将 My 更改为实际应用的名称)。
  • 在构建函数中,这会创建一个 MaterialApp。您可能会将构建各种页面的逻辑放入 materialApp 的 onGenerateRoute - 我发现这可以比动态构建更清晰、更容易地判断正在发生的事情。
  • 如果您通过名称(字符串)在页面之间转换,您应该将名称设为全局常量。
  • 每个页面的有状态或无状态小部件(除非页面足够相似,可以通过一些简单的参数进行区分),在构建函数中将制作脚手架、应用栏、抽屉导航等
  • 可选地,脚手架也可以是它自己的小部件
  • 您的应用栏的小部件(即 CustomAppBar)
  • 用于您的抽屉导航的小部件

还有一些需要注意的事情是:

  1. 按构建函数而不是类拆分内容似乎更快,但事实并非如此。在一个构建函数中有两个小部件(不要被愚弄,调用一个从构建函数返回一个小部件的函数与将代码直接放在函数中以提高性能是一样的)实际上意味着更多的计算每次需要重建小部件时,都需要构建和检查整个类集,而如果您在小部件中使用适当的封装,那么如果小部件树的那部分没有任何变化,则可以跳过很多工作。
  2. 在每个页面中构建 Scaffold、AppBar 和 Drawer 似乎很浪费。然而,由于 Flutter 缓存事物并智能地扫描小部件树的方式,它实际上非常高效,这就是 Flutter 团队推荐的做事方式。
  3. 始终弄清楚您从哪个构建上下文调用东西,然后您可以跟进构建树以确定在调用 .of(context) 时实际调用了哪个小部件。

希望对您有所帮助!

关于dart - 抽屉导航不适用于屏幕内的屏幕,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54540486/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com