问题描述
我正在使用响应时间短的Web UI。而且我想在移动和台式机屏幕宽度特定的屏幕宽度上关闭打开的抽屉,因此,如果我拉伸浏览器,则抽屉应该关闭。
例如,我打开了抽屉(屏幕宽度小于500)
当屏幕宽度大于500时,我希望打开的抽屉自动关闭。
注意:打开抽屉时。我已经有一个代码来检查是否显示按钮菜单抽屉的屏幕宽度。但基本上,当用户打开抽屉然后突然拉开浏览器时,抽屉应该关闭。
下面的代码。感谢您的帮助
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final size = MediaQuery.of(context).size.width;
return Scaffold(
drawer: Drawer(),body: CustomNavBar(screenSize: size),);
}
}
class CustomNavBar extends StatefulWidget {
final double screenSize;
const CustomNavBar({Key key,this.screenSize}) : super(key: key);
@override
_CustomNavBarState createState() => _CustomNavBarState();
}
class _CustomNavBarState extends State<CustomNavBar> {
@override
Widget build(BuildContext context) {
if (Scaffold.of(context).isDrawerOpen && widget.screenSize > 500) {
print("Drawer is Opened");
Scaffold.of(context).openEndDrawer(); //animation error
setState(() {});
}
return widget.screenSize > 500
? Container(color: Colors.red) //desktop screen
: Center(
//mobile screen
child: IconButton(
icon: Icon(Icons.menu),onPressed: () => Scaffold.of(context).openDrawer(),),);
}
}
解决方法
您不必手动关闭抽屉。当屏幕宽度小于500时,为什么不干掉抽屉?
class SampleDrawer extends StatelessWidget {
final GlobalKey<ScaffoldState> k = GlobalKey();
@override
Widget build(BuildContext context) {
// new
final size = MediaQuery.of(context).size.width;
if (k.currentState.isDrawerOpen && size < 500) {
Navigator.pop(context); // close drawer
}
return Scaffold(
key: k,drawer: size > 500 ? Drawer() : null,body: CustomNavBar(),);
}
}
class CustomNavBar extends StatelessWidget {
@override
Widget build(BuildContext context) {
final size = MediaQuery.of(context).size.width;
return size > 500
? Container(color: Colors.red) //desktop screen
: Center( //mobile screen
child: IconButton(
icon: Icon(Icons.menu),onPressed: () => Scaffold.of(context).openDrawer(),),);
}
}
只要更改设备的宽度,便会重新构建脚手架;如果宽度小于500,则会自动省略抽屉。
,这是解决方案。
您就是代码就足够了。只需对您的代码进行几处更改
-
将此
中Scaffold.of(context).openEndDrawer();
包裹在WidgetsBinding.instance.addPostFrameCallback((_) { Scaffold.of(context).openEndDrawer(); //No Error ///The Error was coming,As you're trying to build a widget when it is ///rebuilding widget Tree due to the change in the width of the browser. ///Wrapping it inside ensures that the code will run after the build. });
-
请勿使用
setState(() {});
-
使用520代替500
原因
错误即将到来,因为您正在尝试构建一个小部件时 由于浏览器宽度的变化而重建了“小部件树”。 将此
Scaffold.of(context).openEndDrawer();
包装在WidgetsBinding.instance.addPostFrameCallback((_) {});
内可确保代码在小部件构建完成后运行。
此处是更新的代码
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final size = MediaQuery.of(context).size.width;
print(size);
return Scaffold(
drawer: Drawer(),body: CustomNavBar(
screenSize: size,);
}
}
class CustomNavBar extends StatefulWidget {
final double screenSize;
const CustomNavBar({
Key key,this.screenSize,}) : super(key: key);
@override
_CustomNavBarState createState() => _CustomNavBarState();
}
class _CustomNavBarState extends State<CustomNavBar> {
@override
Widget build(BuildContext context) {
if (Scaffold.of(context).isDrawerOpen && widget.screenSize > 520) {
print("Drawer is Opened");
WidgetsBinding.instance.addPostFrameCallback((_) {
Scaffold.of(context).openEndDrawer(); //No Error
///The error was coming,As you're trying to build a widget when it is
///rebuilding widget Tree due to the change in the width of the browser.
///Wrapping it inside ensure that the code will run after the build.
});
// Don't call setState((){}); Not Required;
// as every time you change the width it rebuilds all the widget again
// setState(() {});
}
return widget.screenSize > 520
? Container(color: Colors.red) //desktop screen
: Center(
//mobile screen
child: IconButton(
icon: Icon(Icons.menu),);
}
}
错误是
The following assertion was thrown while notifying status listeners for
AnimationController:
setState() or markNeedsBuild() called during build.
This Scaffold 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:
Scaffold
The widget which was currently being built when the offending call was made was:
CustomNavBar
提示
将布局生成器用于响应式用户界面。
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context,constraints) {
if (constraints.maxWidth > 800) {
return XScreen();
} else if (constraints.maxWidth < 1200 && constraints.maxWidth > 800) {
return Yscreen()?? ZScreen();
} else {
return XScreen()?? ZScreeen();
}
},);
}