如何在不创建新的小部件树分支的情况下重用相同的布局屏幕
How to reuse the same layout screen without creating a new widget tree branch
我正在开发 Flutter Web 应用程序。
目标是为大部分路由屏幕重用相同的布局屏幕小部件(Drawer、AppBar)。
我已经尝试创建一个新的 Scaffold class 并向每个屏幕添加 body 小部件。
每次导航到新屏幕时都会出现问题。在小部件树上创建了一个新的 (MyScaffold)。所以对性能不好。
我也尝试使用嵌套路由器,问题是 url 不支持嵌套路由器,我无法通过键入 URL.
导航到屏幕
有没有其他正确的方法来处理这个问题。
谢谢
添加代码示例:
import 'package:flutter/material.dart';
void main() => runApp(AppWidget());
class AppWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
initialRoute: '/',
routes: {
'/': (context) => FirstScreen(),
'/second': (context) => SecondScreen(),
},
);
}
}
class FirstScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('First Screen'),
),
body: Center(
child: RaisedButton(
child: Text('Launch screen'),
onPressed: () {
Navigator.pushReplacementNamed(context, '/second');
},
),
),
);
}
}
class SecondScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Second Screen"),
),
body: Center(
child: RaisedButton(
onPressed: () {
Navigator.pushReplacementNamed(context, '/');
},
child: Text('Go back!'),
),
),
);
}
}
我会尽力更好地解释这个问题。
如您所见第一个屏幕和第二个屏幕 具有完全相同的小部件树结构。但是每次 flutter 都会删除 Screen Widget 并创建一个新的。
我还尝试更改代码以创建新的 MyScaffold 并重复使用相同的 Widget class :
class AppWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
initialRoute: '/',
routes: {
'/': (context) => MyScallfold(
bodyWidget: FirstScreen(),
),
'/second': (context) => MyScallfold(
bodyWidget: SecondScreen(),
),
},
);
}
}
class FirstScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return RaisedButton(
onPressed: () {
Navigator.pushReplacementNamed(context, '/second');
},
child: Text('To Screen 2!'),
);
}
}
class SecondScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return RaisedButton(
onPressed: () {
Navigator.pushReplacementNamed(context, '/');
},
child: Text('To Screen 1!'),
);
}
}
class MyScallfold extends StatelessWidget {
Widget bodyWidget;
MyScallfold({this.bodyWidget});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('WebAppTest'),
),
body: bodyWidget,
);
}
}
我注意到每次使用导航时,树的所有小部件都被重建(renderObject #id 已更改)
那么是否可以在flutter中复用同一个RenderObject(AppBar,RichText)来优化性能?
快速回答是否定的,反正现在还没有。当前,当您使用 Navigator 时,它会刷新页面并重建完整视图。
目前在 Flutter web 上最有效的方法是使用 TabController with a TabBarView in a Stateful widget with SingleTickerProviderStateMixin.
它只加载屏幕上的Widget,而不需要重新加载页面来查看其他页面。您的示例如下所示(我添加了过渡到下一页的动画,但您可以将其删除):
import 'package:flutter/material.dart';
TabController tabController;
class MainScreen extends StatefulWidget {
@override
_MainScreenState createState() => _MainScreenState();
}
class _MainScreenState extends State<MainScreen> with SingleTickerProviderStateMixin {
int activeTab = 0;
@override
void initState() {
tabController = TabController(length: 3, vsync: this, initialIndex: 0)
..addListener(() {
setState(() {
activeTab = tabController.index;
});
});
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('WebAppTest'),
),
body: Expanded(
child: TabBarView(
controller: tabController,
children: <Widget>[
FirstScreen(), //Index 0
SecondScreen(), //Index 1
ThirdScreen(), //Index 2
],
),
),
);
}
}
class FirstScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return RaisedButton(
onPressed: () {
tabController.animateTo(2);
},
child: Text('To Screen 3!'),
);
}
}
class SecondScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return RaisedButton(
onPressed: () {
tabController.animateTo(0);
},
child: Text('To Screen 1!'),
);
}
}
class ThirdScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return RaisedButton(
onPressed: () {
tabController.animateTo(1);
},
child: Text('To Screen 2!'),
);
}
}
我正在开发 Flutter Web 应用程序。
目标是为大部分路由屏幕重用相同的布局屏幕小部件(Drawer、AppBar)。
我已经尝试创建一个新的 Scaffold class 并向每个屏幕添加 body 小部件。
每次导航到新屏幕时都会出现问题。在小部件树上创建了一个新的 (MyScaffold)。所以对性能不好。
我也尝试使用嵌套路由器,问题是 url 不支持嵌套路由器,我无法通过键入 URL.
导航到屏幕有没有其他正确的方法来处理这个问题。
谢谢
添加代码示例:
import 'package:flutter/material.dart';
void main() => runApp(AppWidget());
class AppWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
initialRoute: '/',
routes: {
'/': (context) => FirstScreen(),
'/second': (context) => SecondScreen(),
},
);
}
}
class FirstScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('First Screen'),
),
body: Center(
child: RaisedButton(
child: Text('Launch screen'),
onPressed: () {
Navigator.pushReplacementNamed(context, '/second');
},
),
),
);
}
}
class SecondScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Second Screen"),
),
body: Center(
child: RaisedButton(
onPressed: () {
Navigator.pushReplacementNamed(context, '/');
},
child: Text('Go back!'),
),
),
);
}
}
我会尽力更好地解释这个问题。
如您所见第一个屏幕和第二个屏幕 具有完全相同的小部件树结构。但是每次 flutter 都会删除 Screen Widget 并创建一个新的。
我还尝试更改代码以创建新的 MyScaffold 并重复使用相同的 Widget class :
class AppWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
initialRoute: '/',
routes: {
'/': (context) => MyScallfold(
bodyWidget: FirstScreen(),
),
'/second': (context) => MyScallfold(
bodyWidget: SecondScreen(),
),
},
);
}
}
class FirstScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return RaisedButton(
onPressed: () {
Navigator.pushReplacementNamed(context, '/second');
},
child: Text('To Screen 2!'),
);
}
}
class SecondScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return RaisedButton(
onPressed: () {
Navigator.pushReplacementNamed(context, '/');
},
child: Text('To Screen 1!'),
);
}
}
class MyScallfold extends StatelessWidget {
Widget bodyWidget;
MyScallfold({this.bodyWidget});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('WebAppTest'),
),
body: bodyWidget,
);
}
}
我注意到每次使用导航时,树的所有小部件都被重建(renderObject #id 已更改)
那么是否可以在flutter中复用同一个RenderObject(AppBar,RichText)来优化性能?
快速回答是否定的,反正现在还没有。当前,当您使用 Navigator 时,它会刷新页面并重建完整视图。
目前在 Flutter web 上最有效的方法是使用 TabController with a TabBarView in a Stateful widget with SingleTickerProviderStateMixin.
它只加载屏幕上的Widget,而不需要重新加载页面来查看其他页面。您的示例如下所示(我添加了过渡到下一页的动画,但您可以将其删除):
import 'package:flutter/material.dart';
TabController tabController;
class MainScreen extends StatefulWidget {
@override
_MainScreenState createState() => _MainScreenState();
}
class _MainScreenState extends State<MainScreen> with SingleTickerProviderStateMixin {
int activeTab = 0;
@override
void initState() {
tabController = TabController(length: 3, vsync: this, initialIndex: 0)
..addListener(() {
setState(() {
activeTab = tabController.index;
});
});
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('WebAppTest'),
),
body: Expanded(
child: TabBarView(
controller: tabController,
children: <Widget>[
FirstScreen(), //Index 0
SecondScreen(), //Index 1
ThirdScreen(), //Index 2
],
),
),
);
}
}
class FirstScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return RaisedButton(
onPressed: () {
tabController.animateTo(2);
},
child: Text('To Screen 3!'),
);
}
}
class SecondScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return RaisedButton(
onPressed: () {
tabController.animateTo(0);
},
child: Text('To Screen 1!'),
);
}
}
class ThirdScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return RaisedButton(
onPressed: () {
tabController.animateTo(1);
},
child: Text('To Screen 2!'),
);
}
}