Flutter中如何在指定时长后停止Skeletonizer闪烁效果并加载组件数据
解决Skeletonizer持续显示骨架屏不渲染真实组件的问题
你遇到的核心问题是没有控制Skeletonizer的启用状态——当前代码里它一直包裹着整个ListView,所以会持续显示骨架效果,不会切换到真实的输入框、按钮等组件。
具体解决步骤:
- 添加状态变量控制加载状态
在_LoginPageState里声明一个布尔变量,用来标记是否处于骨架屏展示阶段:
bool _isLoading = true;
- 设置延迟切换状态(模拟加载过程)
在initState方法里添加延迟,到时间后关闭骨架屏(如果是真实项目,这里可以替换成异步操作的回调,比如获取完登录配置后再切换):
@override void initState() { super.initState(); // 模拟2秒加载时间,之后切换到真实内容 Future.delayed(const Duration(seconds: 2), () { if(mounted) { // 避免页面已销毁时调用setState报错 setState(() { _isLoading = false; }); } }); }
- 条件渲染骨架屏/真实内容
在build方法里,根据_isLoading的值决定是否用Skeletonizer包裹内容,同时把登录页UI抽成单独方法避免重复代码:
@override Widget build(BuildContext context) { return Scaffold( // ... 保留你原来的Scaffold配置 child: _isLoading ? Skeletonizer(child: _buildLoginContent()) : _buildLoginContent(), ); } // 抽离登录页核心UI为单独方法 Widget _buildLoginContent() { return ListView( shrinkWrap: true, padding: const EdgeInsets.all(50), children: [ Align( alignment: Alignment.center, child: GradientIcon( icon: Icons.lock_rounded, gradient: LinearGradient( colors: [ Colors.lightGreen.shade900, Colors.lightGreen.shade800, Colors.lightGreen.shade700, Colors.lightGreen.shade600, ], ), size: 100, ), ), const SizedBox(height: 25), SizedBox( child: Align( alignment: Alignment.center, child: Text(welcomeMsg, textAlign: TextAlign.center, maxLines: 2, style: GoogleFonts.merriweather( fontSize: 12, fontWeight: FontWeight.bold, color: Colors.grey.shade800, )), ), ), const SizedBox(height: 25), SizedBox( width: MediaQuery.of(context).size.width * 0.75, child: Divider( color: Colors.grey.shade600, indent: 15, endIndent: 15, ), ), const SizedBox(height: 25), SizedBox( width: MediaQuery.of(context).size.width * 0.75, child: CustomTextField( controller: emailController, hintText: 'imranfarid@yandex.com', obscureText: false, labelText: 'Email', prefixIcon: Icons.email_rounded)), const SizedBox(height: 25), SizedBox( width: MediaQuery.of(context).size.width * 0.75, child: CustomTextField( controller: passwordController, hintText: '********', obscureText: true, labelText: 'Password', prefixIcon: Icons.key_rounded)), const SizedBox(height: 25), SizedBox( width: MediaQuery.of(context).size.width * 0.75, child: CustomButton( text: 'LOGIN', onPressed: signUserIn, hpadding: 15, wpadding: 15, borderRadius: 15.0, color: const Color.fromARGB(255, 16, 58, 40)), ), ], ); }
关键说明:
- 抽离
_buildLoginContent方法是为了避免重复编写相同的UI代码,维护更方便 mounted判断是必要的,防止页面在延迟完成前被销毁,导致setState触发报错- 如果登录页有真实异步逻辑(比如拉取欢迎语、接口配置),可以把
Future.delayed替换成对应的异步任务,待任务完成后再切换_isLoading状态
这样修改后,登录页会先显示骨架屏一段时间,之后自动切换到可交互的真实组件。
内容的提问来源于stack exchange,提问作者Imran Farid
相关产品推荐
相关产品推荐

