Flutter 开发实战:封装自定义 Loading 弹窗
在 Flutter 开发中,虽然有一些默认的加载指示器,如,但在实际项目里,它们往往无法满足多样化的设计需求。比如,产品设计要求加载动画要有独特的风格,或者在弹窗上添加额外的文字描述,这时就需要封装自定义的 Loading 弹窗,让其风格与整个应用的设计风格保持一致,同时具备更好的交互性。创建 Loading 弹窗组件:在lib目录下创建一个新的 Dart 文件,比如。在这个文件里,定义一个继承自
目录
在 Flutter 应用开发中,Loading 弹窗是一个常见且重要的组件,它能在数据加载、网络请求等操作时,向用户展示当前的状态,提升用户体验。本文将详细介绍如何在 Flutter 项目中封装一个自定义的 Loading 弹窗。
一、为什么要封装自定义 Loading 弹窗
在 Flutter 开发中,虽然有一些默认的加载指示器,如CircularProgressIndicator
,但在实际项目里,它们往往无法满足多样化的设计需求。比如,产品设计要求加载动画要有独特的风格,或者在弹窗上添加额外的文字描述,这时就需要封装自定义的 Loading 弹窗,让其风格与整个应用的设计风格保持一致,同时具备更好的交互性。
二、准备工作
- 创建 Flutter 项目:如果还没有 Flutter 项目,可以通过 Flutter 命令行工具创建一个新的项目。在终端执行
flutter create custom_loading_demo
,这样就创建了一个名为custom_loading_demo
的 Flutter 项目。 - 熟悉 Flutter 布局和组件:需要对 Flutter 的布局系统(如
Row
、Column
、Container
等)以及常用组件(如AnimatedBuilder
、Opacity
等)有一定的了解,因为在封装 Loading 弹窗时会用到这些知识来构建界面和实现动画效果。
三、封装自定义 Loading 弹窗
- 创建 Loading 弹窗组件:在
lib
目录下创建一个新的 Dart 文件,比如custom_loading.dart
。在这个文件里,定义一个继承自StatelessWidget
的CustomLoading
类。
import 'package:flutter/material.dart';
class CustomLoading extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
// 弹窗整体的样式
color: Colors.black54,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// 加载动画,可以使用CircularProgressIndicator并自定义样式
CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
strokeWidth: 4.0,
),
const SizedBox(height: 16.0),
// 加载提示文字
Text(
'加载中...',
style: TextStyle(color: Colors.white),
)
],
),
),
);
}
}
在这段代码里,Container
设置了半透明的黑色背景,Center
和Column
用于布局,将加载动画和提示文字垂直居中显示。CircularProgressIndicator
设置了白色的进度条颜色和 4 像素的宽度,Text
组件用于显示 “加载中...” 的提示文字。
- 实现弹窗的显示和隐藏逻辑:为了方便在项目中使用这个 Loading 弹窗,需要创建一个工具类来管理它的显示和隐藏。在
lib
目录下创建loading_utils.dart
文件。
import 'package:flutter/material.dart';
import 'custom_loading.dart';
class LoadingUtils {
static OverlayEntry? _overlayEntry;
static void showLoading(BuildContext context) {
if (_overlayEntry != null) return;
_overlayEntry = OverlayEntry(
builder: (context) => CustomLoading(),
);
Overlay.of(context)?.insert(_overlayEntry!);
}
static void hideLoading() {
_overlayEntry?.remove();
_overlayEntry = null;
}
}
在LoadingUtils
类中,_overlayEntry
用于存储弹窗的OverlayEntry
对象。showLoading
方法负责创建并插入OverlayEntry
到Overlay
中,从而显示 Loading 弹窗;hideLoading
方法则用于移除OverlayEntry
,隐藏 Loading 弹窗。
四、在项目中使用自定义 Loading 弹窗
- 模拟数据加载场景:在
lib/main.dart
文件的MyHomePage
类中,添加一个按钮点击事件来模拟数据加载过程,并在加载前后显示和隐藏 Loading 弹窗。
import 'package:flutter/material.dart';
import 'loading_utils.dart';
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () async {
// 显示Loading弹窗
LoadingUtils.showLoading(context);
// 模拟数据加载,这里使用Future.delayed延迟2秒
await Future.delayed(const Duration(seconds: 2));
// 隐藏Loading弹窗
LoadingUtils.hideLoading();
},
child: const Text('点击加载数据'),
)
],
),
),
);
}
}
在上述代码中,当点击按钮时,先调用LoadingUtils.showLoading(context)
显示 Loading 弹窗,然后通过Future.delayed
模拟 2 秒的数据加载过程,加载完成后调用LoadingUtils.hideLoading()
隐藏 Loading 弹窗。
五、进一步优化
- 添加动画效果:可以使用
AnimatedBuilder
结合Opacity
组件,为 Loading 弹窗添加淡入淡出的动画效果。在custom_loading.dart
文件的CustomLoading
类中修改代码如下:
import 'package:flutter/material.dart';
class CustomLoading extends StatefulWidget {
@override
_CustomLoadingState createState() => _CustomLoadingState();
}
class _CustomLoadingState extends State<CustomLoading> with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _opacityAnimation;
@override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 300),
);
_opacityAnimation = Tween<double>(begin: 0.0, end: 1.0).animate(_controller);
_controller.forward();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _opacityAnimation,
builder: (context, child) {
return Opacity(
opacity: _opacityAnimation.value,
child: Container(
color: Colors.black54,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
strokeWidth: 4.0,
),
const SizedBox(height: 16.0),
Text(
'加载中...',
style: TextStyle(color: Colors.white),
)
],
),
),
),
);
},
);
}
}
这里将CustomLoading
改为StatefulWidget
,并使用AnimationController
和Tween
创建了一个淡入动画,在initState
中启动动画,在dispose
中释放资源。通过AnimatedBuilder
和Opacity
组件实现了 Loading 弹窗的淡入效果。
- 自定义弹窗内容:可以在
CustomLoading
类中添加参数,让使用者可以自定义加载动画和提示文字。
import 'package:flutter/material.dart';
class CustomLoading extends StatefulWidget {
final Widget? loadingIndicator;
final String? loadingText;
const CustomLoading({this.loadingIndicator, this.loadingText});
@override
_CustomLoadingState createState() => _CustomLoadingState();
}
class _CustomLoadingState extends State<CustomLoading> with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _opacityAnimation;
@override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 300),
);
_opacityAnimation = Tween<double>(begin: 0.0, end: 1.0).animate(_controller);
_controller.forward();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _opacityAnimation,
builder: (context, child) {
return Opacity(
opacity: _opacityAnimation.value,
child: Container(
color: Colors.black54,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
widget.loadingIndicator?? CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
strokeWidth: 4.0,
),
const SizedBox(height: 16.0),
Text(
widget.loadingText?? '加载中...',
style: TextStyle(color: Colors.white),
)
],
),
),
),
);
},
);
}
}
这样,在使用CustomLoading
时,可以传入自定义的加载动画和提示文字,例如:
LoadingUtils.showLoading(context, customLoading: CustomLoading(
loadingIndicator: SizedBox(
width: 50.0,
height: 50.0,
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(Colors.blue),
strokeWidth: 5.0,
),
),
loadingText: '数据加载中,请稍候...'
));
六、总结
通过以上步骤,我们成功地在 Flutter 项目中封装了一个自定义的 Loading 弹窗,并实现了显示、隐藏逻辑以及动画效果的优化。在实际项目开发中,根据不同的需求,还可以进一步扩展和优化这个 Loading 弹窗,比如添加更多的动画效果、支持不同的弹窗样式等。希望这篇博客能帮助你在 Flutter 开发中更好地处理加载状态的显示,提升应用的用户体验。
更多推荐
所有评论(0)