Flutter预渲染页面插件prerender的使用
Flutter预渲染页面插件prerender的使用
Prerender
小部件允许构建依赖于其他小部件大小的子树。
Flutter的渲染管道提供了父级大小信息,但在build
方法中不允许计算其他小部件的大小。Prerender
包通过在单个帧内测量一个小部件并延迟最终构建直到其尺寸已知来解决此问题。
入门指南
Prerender
小部件通过以下几步解决其布局以访问目标的尺寸:
- 渲染对象将
target
作为Prerender
的唯一子项进行布局,允许目标填充父项。 - 渲染对象存储计算出的尺寸,并调用
builder
函数,传递目标的解析尺寸。 builder
回调根据之前计算的布局决定最终的子项小部件树形状。
重新构建具有不同目标小部件的树将导致builder
再次被调用,并传递更新的目标尺寸。
注意
由于`Prerender`试图解决的问题性质,它需要计算测量小部件的推测布局。这意味着运行推测布局的限制以及每次构建时额外布局计算的性能考虑。
使用方法
在pubspec.yaml
中添加依赖:
dependencies:
prerender: ^1.0.0
将依赖于某些小部件布局的小部件树包装起来:
Prerender(
// 提供您想要测量的小部件:
target: ...,
// 使用计算出的布局构建实际的子项:
builder: (context, childSize, child) {
...
},
)
例如,仅当有足够的水平空间时才在标题前添加头像:
Prerender(
target: Title(),
builder: (context, childSize, child) {
return Row(
children: [
if (childSize.width < 200) Avatar(),
child,
],
);
},
)
单帧渲染
除了对构建小部件有更细粒度的控制外,使用Prerender
的另一个关键优势是在单个帧内访问和使用其他小部件的尺寸信息:
// 使用 GlobalKey(命令式)
final titleKey = GlobalKey();
Widget build(BuildContext context) {
var titleSize = Size.zero;
final renderObject = titleKey.currentContext?.findRenderObject();
if (renderObject != null) {
titleSize = (renderObject as RenderBox).size;
}
return Row(
children: [
// 大小始终落后一个帧。
if (titleSize.width < 200) Avatar(),
Title(key: titleKey),
],
);
}
// 使用 Prerender(声明式)
Widget build(BuildContext context) {
return Prerender(
target: Title(),
builder: (context, childSize, child) {
return Row(
children: [
if (childSize.width < 200) Avatar(),
child,
],
);
},
);
}
示例
扩展文本
仅在文本宽度大于可用水平区域时显示展开按钮。
固定底部
如果内容小于可用区域,则将底部按钮固定到屏幕底部边缘。
响应式表单
在折叠状态下,将底部表单的高度与主体的垂直尺寸对齐,以防止显示空白区域。
完整示例代码
import 'package:example/examples/expanding_text.dart';
import 'package:example/examples/responsive_sheet.dart';
import 'package:example/examples/sticking_footer.dart';
import 'package:flutter/material.dart';
void main() {
runApp(const ExamplesApp());
}
class ExamplesApp extends StatefulWidget {
const ExamplesApp({super.key});
[@override](/user/override)
State<ExamplesApp> createState() => _ExamplesAppState();
}
class _ExamplesAppState extends State<ExamplesApp> {
final items = [
('扩展文本', const ExpandingTextExample()),
('固定底部', const StickingFooterExample()),
('响应式表单', const ResponsiveSheetExample()),
];
late var currentItem = items.last;
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: AppBar(
centerTitle: false,
title: Text(currentItem.$1),
),
drawer: Drawer(
child: Column(
children: [
for (var (item) in items)
DrawerItem(
title: item.$1,
onSelect: () {
setState(() => currentItem = item);
},
),
],
),
),
body: currentItem.$2,
),
);
}
}
class DrawerItem extends StatelessWidget {
const DrawerItem({
super.key,
required this.title,
required this.onSelect,
});
final String title;
final VoidCallback onSelect;
[@override](/user/override)
Widget build(BuildContext context) {
return ListTile(
title: Text(title),
onTap: () {
onSelect();
Scaffold.of(context).closeDrawer();
},
);
}
}
更多关于Flutter预渲染页面插件prerender的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter预渲染页面插件prerender的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
在Flutter中,预渲染页面可以提升应用的启动速度和用户体验,尤其是在需要加载复杂内容或网络请求的场景。prerender
并不是一个官方的Flutter插件,但你可以通过自定义的方式实现页面预渲染。以下是一个基本的步骤和示例,展示如何在Flutter中实现页面预渲染。
1. 创建一个自定义的预渲染页面
你可以使用 FutureBuilder
或 StreamBuilder
来实现页面的预渲染。在这里,我们将使用 FutureBuilder
来模拟一个异步加载数据并预渲染页面的过程。
import 'package:flutter/material.dart';
class PreRenderedPage extends StatelessWidget {
final Future<String> futureData;
PreRenderedPage({required this.futureData});
@override
Widget build(BuildContext context) {
return FutureBuilder<String>(
future: futureData,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
} else if (snapshot.hasError) {
return Center(child: Text('Error: ${snapshot.error}'));
} else {
return Scaffold(
appBar: AppBar(title: Text('Pre-Rendered Page')),
body: Center(child: Text('Data: ${snapshot.data}')),
);
}
},
);
}
}
2. 在应用启动时预渲染页面
你可以在应用启动时预加载数据,并将预渲染的页面缓存起来,以便在需要时快速显示。
import 'package:flutter/material.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// 预加载数据
final futureData = fetchData();
runApp(MyApp(futureData: futureData));
}
Future<String> fetchData() async {
// 模拟一个异步网络请求
await Future.delayed(Duration(seconds: 2));
return 'Hello, Pre-Rendered World!';
}
class MyApp extends StatelessWidget {
final Future<String> futureData;
MyApp({required this.futureData});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: PreRenderedPage(futureData: futureData),
);
}
}
3. 在需要时显示预渲染的页面
当你需要显示预渲染的页面时,可以直接导航到该页面,而无需等待数据加载。
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => PreRenderedPage(futureData: futureData),
),
);
4. 使用 PageStorage
或 Provider
进行状态管理
为了进一步提升性能,你可以使用 PageStorage
或状态管理工具(如 Provider
)来缓存页面的状态,以避免重复加载数据。
5. 使用 SizedBox
或 Placeholder
优化用户体验
在数据加载过程中,你可以使用 SizedBox
或 Placeholder
来占位,以避免页面布局发生抖动。
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
}