flutter如何实现骨架屏效果

在Flutter中如何实现骨架屏效果?最近在优化App的加载体验,想在数据加载完成前显示占位骨架屏,但不太清楚具体实现方式。请问有哪些常用的实现方案?是通过第三方库还是自定义实现更合适?希望能分享一些具体的实现代码示例和最佳实践。

2 回复

在Flutter中实现骨架屏效果,可使用shimmer库或自定义渐变遮罩。通过SkeletonAnimationContainer结合LinearGradient创建灰色占位块,模拟加载状态。适用于列表、卡片等组件,提升用户体验。

更多关于flutter如何实现骨架屏效果的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


在Flutter中实现骨架屏效果可以通过以下几种方式:

1. 使用shimmer库(推荐)

首先添加依赖:

dependencies:
  shimmer: ^2.0.0

基本使用:

import 'package:shimmer/shimmer.dart';

Shimmer(
  gradient: LinearGradient(
    colors: [
      Colors.grey[300]!,
      Colors.grey[100]!,
      Colors.grey[300]!,
    ],
  ),
  child: Column(
    children: [
      Container(
        width: double.infinity,
        height: 20,
        color: Colors.white,
      ),
      SizedBox(height: 10),
      Container(
        width: 200,
        height: 20,
        color: Colors.white,
      ),
    ],
  ),
)

2. 自定义骨架屏组件

class SkeletonItem extends StatelessWidget {
  final double width;
  final double height;
  
  const SkeletonItem({
    Key? key,
    required this.width,
    required this.height,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      width: width,
      height: height,
      decoration: BoxDecoration(
        color: Colors.grey[300],
        borderRadius: BorderRadius.circular(4),
      ),
    );
  }
}

// 使用示例
Column(
  children: [
    SkeletonItem(width: double.infinity, height: 20),
    SizedBox(height: 10),
    SkeletonItem(width: 200, height: 20),
    SizedBox(height: 10),
    SkeletonItem(width: 150, height: 20),
  ],
)

3. 完整页面骨架屏示例

Widget buildSkeletonScreen() {
  return Padding(
    padding: EdgeInsets.all(16),
    child: Column(
      children: [
        // 头像区域
        Row(
          children: [
            Container(
              width: 60,
              height: 60,
              decoration: BoxDecoration(
                color: Colors.grey[300],
                shape: BoxShape.circle,
              ),
            ),
            SizedBox(width: 16),
            Expanded(
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Container(
                    width: double.infinity,
                    height: 16,
                    color: Colors.grey[300],
                  ),
                  SizedBox(height: 8),
                  Container(
                    width: 120,
                    height: 14,
                    color: Colors.grey[300],
                  ),
                ],
              ),
            ),
          ],
        ),
        SizedBox(height: 24),
        // 内容区域
        Expanded(
          child: ListView.builder(
            itemCount: 5,
            itemBuilder: (context, index) {
              return Container(
                margin: EdgeInsets.only(bottom: 16),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Container(
                      width: double.infinity,
                      height: 120,
                      color: Colors.grey[300],
                    ),
                    SizedBox(height: 8),
                    Container(
                      width: double.infinity,
                      height: 16,
                      color: Colors.grey[300],
                    ),
                    SizedBox(height: 4),
                    Container(
                      width: 200,
                      height: 14,
                      color: Colors.grey[300],
                    ),
                  ],
                ),
              );
            },
          ),
        ),
      ],
    ),
  );
}

使用技巧

  1. 状态管理:使用Visibility或条件渲染在数据加载时显示骨架屏
  2. 动画效果:结合AnimationController实现渐变动画
  3. 真实布局:骨架屏布局应与真实UI布局保持一致

这种方式可以有效提升用户体验,让用户感知到内容正在加载中。

回到顶部