You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter中如何在指定时长后停止Skeletonizer闪烁效果并加载组件数据

解决Skeletonizer持续显示骨架屏不渲染真实组件的问题

你遇到的核心问题是没有控制Skeletonizer的启用状态——当前代码里它一直包裹着整个ListView,所以会持续显示骨架效果,不会切换到真实的输入框、按钮等组件。

具体解决步骤:

  1. 添加状态变量控制加载状态
    在_LoginPageState里声明一个布尔变量,用来标记是否处于骨架屏展示阶段:
bool _isLoading = true;
  1. 设置延迟切换状态(模拟加载过程)
    在initState方法里添加延迟,到时间后关闭骨架屏(如果是真实项目,这里可以替换成异步操作的回调,比如获取完登录配置后再切换):
@override
void initState() {
  super.initState();
  // 模拟2秒加载时间,之后切换到真实内容
  Future.delayed(const Duration(seconds: 2), () {
    if(mounted) { // 避免页面已销毁时调用setState报错
      setState(() {
        _isLoading = false;
      });
    }
  });
}
  1. 条件渲染骨架屏/真实内容
    在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 16:02:04