[Flutter] shimmer 패키지로 스켈레톤 UI 적용하기

구현 목표

테스트를 위해 로딩 속도를 일부러 지연시켰다

기존에는 화면 중앙에 로딩 스피너를 배치했는데,

데이터를 불러온 뒤에 시선이 다시 화면 상단으로 이동해야 하는 점이 다소 불편하다고 느꼈다.

 

그래서 시선 이동을 최소화하고 사용자 경험을 높이기 위해

홈 화면 로딩 시 로딩 스피너 대신 스켈레톤 UI를 적용하기로 했다.

 

shimmer 패키지

플러터에서 손쉽게 shimmer 효과를 적용할 수 있도록 도와주는 패키지다.

스켈레톤 UI를 만들 때 자주 활용되며, `baseColor`, `highlightColor`, `child`만 지정하면 간단하게 적용할 수 있다.

 

그 외에는 다음과 같은 옵션들을 제공한다.

 

shimmer | Flutter package

A package provides an easy way to add shimmer effect in Flutter project

pub.dev

 

공용 스켈레톤 위젯 만들기

홈 화면 구조가 단순하기 때문에, 공통 스켈레톤 카드 위젯을 만들고 높이만 전달하기로 했다.

 

import 'package:flutter/material.dart';
import 'package:shimmer/shimmer.dart';

// 공용 스켈레톤 카드
class SkeletonCard extends StatelessWidget {
  final double height;

  const SkeletonCard({
    super.key,
    required this.height,
  });

  @override
  Widget build(BuildContext context) {
    return Shimmer.fromColors(
      baseColor: Colors.grey[200]!,
      highlightColor: Colors.grey[100]!,
      child: Padding(
        padding: const EdgeInsets.all(2.0),
        child: Container(
          height: height,
          decoration: BoxDecoration(
            color: Colors.grey[200],
            borderRadius: BorderRadius.circular(12),
          ),
        ),
      ),
    );
  }
}

 

홈 화면 전용 스켈레톤 UI

// 로딩 시 표시하는 스켈레톤 UI 위젯
class HomeBodySkeleton extends StatelessWidget {
  const HomeBodySkeleton({super.key});

  @override
  Widget build(BuildContext context) {
    return const Padding(
      padding: EdgeInsets.symmetric(horizontal: 2.0),
      child: Column(
        children: [
          SizedBox(height: 1),
          SkeletonCard(height: 110), // 첫 번째 카드
          SizedBox(height: 11),
          SkeletonCard(height: 60), // 두 번째 카드
        ],
      ),
    );
  }
}

홈 화면의 구조와 크기에 맞춰 `HomeBodySkeleton`이라는 위젯을 따로 만들었다.

 

isLoading ? const HomeBodySkeleton() : Column(...)

`isLoading` 여부에 따라 스켈레톤 UI 또는 실제 화면을 보여준다.