Stat#
대시보드나 리포트에서 주요 수치를 레이블, 값, 보조 텍스트, 트렌드 방향과 함께 표시하는 통계 컴포넌트입니다.
Live Preview#
class StatDefaultExample extends StatefulComponent {
const StatDefaultExample({super.key});
@override
State<StatDefaultExample> createState() => _StatDefaultExampleState();
}
class _StatDefaultExampleState extends State<StatDefaultExample> {
@override
Component build(BuildContext context) {
return CoStat(
label: 'Total Revenue',
value: '$45,231.89',
change: '+20.1%',
changeType: CoreStatChangeType.positive,
);
}
}
class StatDefaultExample extends StatefulWidget {
const StatDefaultExample({super.key});
@override
State<StatDefaultExample> createState() => _StatDefaultExampleState();
}
class _StatDefaultExampleState extends State<StatDefaultExample> {
@override
Widget build(BuildContext context) {
return const CoStat(
label: 'Total Revenue',
value: '$45,231.89',
change: '+20.1%',
changeType: CoreStatChangeType.positive,
);
}
}
사용 시기 (When to Use)#
이 컴포넌트를 사용하세요:
- 대시보드의 KPI(핵심 성과 지표)를 카드 형태로 표시할 때
- 매출, 사용자 수, 방문자 수 등 주요 지표를 강조하여 표시할 때
- 이전 기간 대비 증감 트렌드를 함께 보여줄 때
- 분석 리포트의 요약 수치를 그리드로 나열할 때
대신 다른 컴포넌트를 사용하세요:
Progress: 완료율이나 목표 달성률을 시각적으로 표현할 때NumberTicker: 단순히 애니메이션 숫자만 필요할 때 (레이블, 트렌드 불필요)Text: 레이블 없이 수치만 간단히 표시할 때
기본 사용법 (Basic Usage)#
// 기본 통계
Stat(
label: '총 사용자',
value: '128,450',
)
// 트렌드 포함
Stat(
label: '이번 달 매출',
value: '₩12,450,000',
helpText: '지난 달 대비',
trend: StatTrend.up,
trendValue: '+12.5%',
)
// 하락 트렌드
Stat(
label: '이탈률',
value: '3.2%',
helpText: '지난 주 대비',
trend: StatTrend.down,
trendValue: '-0.8%',
)
// 중립 트렌드
Stat(
label: '평균 응답 시간',
value: '245ms',
trend: StatTrend.neutral,
trendValue: '변동 없음',
)
// 기본 통계
Stat(
label: '총 사용자',
value: '128,450',
)
// 상승 트렌드
Stat(
label: '이번 달 매출',
value: '₩12,450,000',
change: '+12.5%',
changeType: StatChangeType.positive,
)
// 하락 트렌드
Stat(
label: '이탈률',
value: '3.2%',
change: '-0.8%',
changeType: StatChangeType.negative,
)
// 중립 상태
Stat(
label: '평균 응답 시간',
value: '245ms',
change: '변동 없음',
changeType: StatChangeType.neutral,
)
Props / Parameters#
| 속성 | 타입 | 기본값 | 설명 |
|---|---|---|---|
label | String | 필수 | 통계 항목 레이블 |
value |
dynamic |
필수 | 표시할 수치 (String 또는 Widget) |
helpText |
String? |
null |
값 하단에 표시할 보조 설명 |
trend |
StatTrend? |
null |
트렌드 방향 (up / down / neutral) |
trendValue |
String? |
null |
트렌드 수치 텍스트 |
변형 (Variants)#
상승 트렌드#
Stat(
label: '신규 가입',
value: '1,284',
trend: StatTrend.up,
trendValue: '+8.2%',
)
하락 트렌드#
Stat(
label: '취소율',
value: '1.4%',
trend: StatTrend.down,
trendValue: '-0.3%',
)
중립#
Stat(
label: '활성 세션',
value: '892',
trend: StatTrend.neutral,
trendValue: '±0%',
)
그리드 레이아웃#
여러 Stat을 그리드로 배치하여 대시보드를 구성합니다.
GridView.count(
crossAxisCount: 3,
children: [
Stat(label: '총 사용자', value: '128,450', trend: StatTrend.up, trendValue: '+5%'),
Stat(label: '매출', value: '₩12.4M', trend: StatTrend.up, trendValue: '+12%'),
Stat(label: '이탈률', value: '3.2%', trend: StatTrend.down, trendValue: '-0.8%'),
],
)
동작 스펙 (Behavior)#
인터랙션#
- Stat은 기본적으로 표시 전용 컴포넌트입니다.
value에CouiNumberTicker를 전달하면 값 변경 시 애니메이션 적용 가능
상태 전환#
- 값 변경:
value가 Widget인 경우 해당 Widget의 애니메이션에 따름 - 트렌드 변경: 아이콘 색상 즉시 변경 (up: 초록, down: 빨강, neutral: 회색)
애니메이션#
- 기본: 없음
value에CouiNumberTicker사용 시 숫자 롤링 애니메이션 적용
사용 가이드라인 (Usage Guidelines)#
✅ Do#
NumberTicker와 조합하여 살아있는 대시보드 구현
CouiStat(
label: '실시간 방문자',
value: CouiNumberTicker(
value: realtimeVisitors,
separator: ',',
duration: Duration(milliseconds: 400),
style: TextStyle(fontSize: 40, fontWeight: FontWeight.bold),
),
helpText: '현재 접속 중',
trend: realtimeVisitors > previousVisitors ? StatTrend.up : StatTrend.down,
trendValue: '${(realtimeVisitors - previousVisitors).abs()} 명',
)
NumberTicker와 조합하면 실시간 데이터 변화를 생동감 있게 표현할 수 있습니다.
❌ Don't#
트렌드 방향과 trendValue의 의미 불일치 금지
// ❌ 트렌드 방향과 값이 모순됨
CouiStat(
label: '이탈률',
value: '3.2%',
trend: StatTrend.down, // 하락
trendValue: '+0.5%', // 상승 값 — 혼란스러움
)
트렌드 방향과 trendValue가 일치하지 않으면 사용자가 혼란스러워합니다. 이탈률 감소는 긍정적이므로 StatTrend.down과 -0.5%
또는 맥락에 따라 StatTrend.up으로 표시하세요.
✅ Do#
비교 기간을 helpText로 명시
CouiStat(
label: '월간 매출',
value: '₩12,450,000',
helpText: '지난 달(₩11,150,000) 대비',
trend: StatTrend.up,
trendValue: '+11.7%',
)
어느 기간과 비교한 값인지 명시하면 수치의 의미를 정확히 전달할 수 있습니다.
❌ Don't#
너무 많은 Stat을 한 화면에 나열 금지
// ❌ 15개의 KPI를 한 화면에 나열
GridView.count(
crossAxisCount: 5,
children: List.generate(15, (i) => CouiStat(...)),
)
너무 많은 통계는 인지 과부하를 유발합니다. 한 화면에는 가장 중요한 4~8개의 KPI만 표시하세요.
✅ Do#
지표 값의 변화량(delta)을 함께 표시하세요.
CouiStat(
label: '월간 매출',
value: '₩12,450,000',
delta: '+15.3%',
deltaType: DeltaType.positive, // 초록색으로 표시
)
현재 값과 이전 기간 대비 변화율을 함께 보여주면 트렌드를 한눈에 파악할 수 있어 의사결정에 도움이 됩니다.
❌ Don't#
단위 없이 숫자만 표시하지 마세요.
// ❌ 단위가 없어 의미를 알 수 없는 숫자
CouiStat(
label: '방문자',
value: '15234', // 명/일/월 구분 불가
)
숫자만 있으면 무엇을 기준으로 한 값인지 알 수 없습니다. 단위(명, 원, %, 건 등)를 반드시 함께 표시하세요.
접근성 (Accessibility)#
키보드 인터랙션#
해당 없음. Stat은 기본적으로 인터랙티브 요소가 아닙니다.
스크린 리더#
-
Flutter: 레이블, 값, 트렌드를 순서대로 읽는
Semantics적용 권장 ('총 사용자, 128,450명, 5% 상승') -
Web:
dl/dt/dd구조 또는 적절한aria-label적용
터치 타겟#
해당 없음. 표시 전용 요소. (클릭 시 상세 보기로 이동하는 경우 48x48dp 보장)
크로스 플랫폼 차이점 (Platform Differences)#
| 항목 | Flutter | Web |
|---|---|---|
| 클래스명 | CouiStat | Stat |
| value 타입 | dynamic (String 또는 Widget) |
dynamic (String 또는 Widget) |
| 트렌드 아이콘 | Material Icons | SVG 아이콘 |
관련 컴포넌트 (Related Components)#
- NumberTicker: 애니메이션 숫자를 value로 사용할 때
- Progress: 목표 대비 진행률을 바 형태로 표시할 때
- Card: Stat을 카드로 감싸 배경과 그림자를 추가할 때
조합 예제#
// Stat + Card + NumberTicker 조합
GridView.count(
crossAxisCount: 3,
crossAxisSpacing: 16,
mainAxisSpacing: 16,
children: kpiData.map((kpi) => CouiCard(
child: CouiStat(
label: kpi.label,
value: CouiNumberTicker(
value: kpi.value,
separator: ',',
prefix: kpi.prefix,
style: TextStyle(fontSize: 32, fontWeight: FontWeight.bold),
),
helpText: '지난 달 대비',
trend: kpi.isUp ? StatTrend.up : StatTrend.down,
trendValue: kpi.changePercent,
),
)).toList(),
)