본문 바로가기
flutter/Widget of the Week

Flutter[플러터] / CircularProgressIndicator 를 사용하여 동작이 실행 중임을 나타내는 로딩 화면 보여주기 (로더, 서큘러, 프로그래스 인디케이터, 바, 진행률 표시) CircularProgressIndicator (Flutter Widget of the Week)

by ch5c 2025. 7. 1.
반응형

CircularProgressIndicator class

애플리케이션이 실행 중임을 나타내기 위해 회전하는 Material Design 원형 진행률 표시기입니다.

https://youtu.be/O-rhXZLtpv0

공식 문서 코드

 

 


화면에서 어떠한 동작이 로딩 중이라는 것을 표시하기 위해선 어떤 방법이 가장 좋을까? 단연콘데 로더 동작을 만들어 놓으면 좋을 것이다. 근데 이제 여기에서 일반 사용자에게 가장 익숙한 로더는 무엇인가 하면 바로 원형 프로그래스 인디케이터일 것이다. 근데 또 이런 인디케이터를 직접 만들려고 하면 골치 아플 것인데 이것을 아주 간단하게 바로 사용할 수 있도록 만든 위젯이 바로 CircularProgressIndicator이다.

CircularProgressIndicator 위젯은 원형으로 로딩 상태를 나타내는 데 사용되는 인디케이터이다. 보통 비동기 작업이 진행 중임을 사용자에게 시각적으로 알릴 때 사용된다. 바로 알아보자.

하위 속성
속성명 타입 기본값 설명
value double? null 0.0에서 1.0 사이의 진행률 값
backgroundColor Color? null 트랙(배경)의 색상
color Color? null 진행 표시 선의 색상
valueColor Animation<Color?>? null 애니메이션 가능한 색상. `value`가 null일 때 사용
strokeWidth double? 4.0 원을 그릴 때 사용하는 선의 두께
strokeAlign double? 상황에 따라 다름 선의 위치: 내부(-1.0), 중심(0.0), 외부(1.0)
strokeCap StrokeCap? null 선 끝의 스타일. round, butt, square 중 선택 가능
constraints BoxConstraints? null 최소/최대 크기 지정
trackGap double? 4 원형 트랙과 진행 표시 사이의 간격
year2023 bool? true Material 3 스타일 사용 여부 (deprecated)
padding EdgeInsetsGeometry? Material 3: zero 트랙과 외곽 사이의 여백
semanticsLabel String? null 접근성을 위한 레이블 텍스트
semanticsValue String? null 접근성을 위한 값 설명

 

사용하는 방법은 정말 간단한데 그냥 CircularProgressIndicator 위젯을 사용해 주면 끝이다.

Center(
  child: CircularProgressIndicator(),
)

이렇게 적고 실행을 하면 무한히 회전하고 있는 인디케이터를 볼 수 있을 것이다.

어째서 무한히 회전하고 있냐고 한다면 그 비밀은 value에 있다.

value의 기본값은 null이다. 즉 원래 value0.0에서 1.0 사이의 double 값을 넣어줘야 정적 진행 상태 표시가 되게 되는데 그 어떤 값도 아닌 null이 기본으로 들어가 있음으로 완료가 되지 않고 계속 회전하는 것이다.

그러니 진행률을 표시하고 싶다면 value를 사용하면 될 것이다.

CircularProgressIndicator(
  value: 0.7,
)

이렇게 value에 원하는 값을 넣으면 그 값에 따라 인디케이터가 딱 그 자리에 멈춰버린다.

당연하겠지만 이렇게는 사용 안 한다.. 하지만 이렇게 값을 지정해 줘서 사용하면 로더에 사용하는 것이 아니라 다른 방면에 사용할 수도 있을 것이다. 여러 가지 디자인이 가능하니 말이다.

예를 들어 영화 사이트가 있다고 하면 영화의 관객 만족도 같은 것을 이 위젯으로 표시할 수도 있을 것이다.

먼저 색상을 바꿔보자. 만약 API에서 관객의 만족도가 70% 라는 값을 얻고 그것을 value로 치환한다고 가정해 본다면 색상은 초록이 좋을 것 같다. 70% 정도면 나쁘지 않은 편 아닌가?

CircularProgressIndicator(
  value: 0.7,
  color: Colors.green,
)

여기다가 조금 더 그래프 느낌이 나게 선두께를 키우고 현재 비어있는 인디케이터 부분을 다른 색상으로 채워주면 좋을 것이다.

CircularProgressIndicator(
  value: 0.7,
  color: Colors.green,
  strokeWidth: 8,
  strokeCap: StrokeCap.round, // 선 끝의 스타일
  backgroundColor: Colors.grey[300], // 2차 색상 (비어있는 부분)
)

이제 안에다가 Stack으로 뭔가 숫자 같은 거 넣어주면 좀 이상한 방향(?)으로 이 CircularProgressIndicator 위젯을 사용해 볼 수 있게 된다.

자 그렇다면 이제 진짜 용도인 로더에 사용해 보자.

먼저 대표적으로 사용되는 곳은 Image.network 속 일 것이다.

여기서 CircularProgressIndicator를 로더로 사용하려면 Image.network의 파라미터인 loadingBuilder를 사용해 주면 된다.

Image.network(
  'https://flutter.github.io/assets-for-api-docs/assets/widgets/owl.jpg',
  loadingBuilder: (context, child, loadingProgress) {
    return loadingProgress == null ? child : CircularProgressIndicator();
  },
)

 

이렇게 작성해 주면 엄청 쉽게 로더 기능을 완성할 수 있는데 그래도 가볍게 설명을 하고 넘어가겠다.

일단 loadingBuilder는 이미지가 로딩중일 때와 로딩 완료 후를 구분해 UI를 보여주는 빌더 함수이다.

여기서 child는 이미지 로딩이 완료되면 보여줄 이미지 위젯이고 loadingProgress는 로딩 중이면 non-null, 완료되면 null 상태를 가지게 돼서 로딩이 끝나게 된다.

즉 로딩 중일 때는 CircularProgressIndicator를 표시하게 되고 로딩이 완료된다면 child(이미지)를 표시하게 되는 것이다.

 

근데 이것 또한 조금은 불편한 감이 없지 않아 있다. 무엇이 불편한가 하면 유저에게 이 사진이 얼마나 로딩되었는지를 알릴 수 없다는 점 말이다. 그렇다면 이 이미지가 로딩되는 것에 맞춰 인디케이터가 채워진다면 좋지 않겠는가? 그것 또한 쉽게 만들 수 있다.

Image.network(
  'https://flutter.github.io/assets-for-api-docs/assets/widgets/owl.jpg',
  loadingBuilder: (context, child, loadingProgress) {
    if (loadingProgress == null) return child;
    double progress = loadingProgress.cumulativeBytesLoaded /
        loadingProgress.expectedTotalBytes!;
    return CircularProgressIndicator(value: progress);
  },
)

이렇게 하면 Image.network에서 이미지가 로드되는 동안 진행 상태에 따라 로딩 인디케이터를 보여주는 loadingBuilder를 완성시킬 수 있다.

자 간단하게 살펴보자면

if (loadingProgress == null) return child;

먼저 로딩이 끝났으면 이미지를 보여주게 되어 있다.

이제 그다음이 문제일 것인데

double progress = loadingProgress.cumulativeBytesLoaded /
    loadingProgress.expectedTotalBytes!;

이것은 현재까지 다운로드한 바이트 수를 전체 이미지 크기로 나눠 0.0 ~ 1.0 사이의 로딩 비율로 계산한 것이다.

그리고 이제 이 값을 CircularProgressIndicatorvalue로 사용해 주면 완성이 되는 것이다.

 

 

이렇게 CircularProgressIndicator 위젯의 사용법을 간단히 알아보았다. 보통은 후자보다는 전자의 로더 코드를 많이 사용하곤 한다지만 그래도 후자의 코드도 알아두면 분명 좋을 것이다. 도움이 되었길 바라며 마치겠다.

반응형