StarRating#
별 아이콘을 사용하여 평점을 입력하거나 표시하는 컴포넌트입니다. 반별(half-star), 커스텀 별 모양, 드래그 인터랙션을 지원합니다.
Live Preview#
class StarRatingDefaultExample extends StatefulComponent {
const StarRatingDefaultExample({super.key});
@override
State<StarRatingDefaultExample> createState() =>
_StarRatingDefaultExampleState();
}
class _StarRatingDefaultExampleState extends State<StarRatingDefaultExample> {
double _value = 3;
@override
Component build(BuildContext context) {
return StarRating(
value: _value,
onChanged: (v) => setState(() => _value = v),
);
}
}
class StarRatingDefaultExample extends StatefulWidget {
const StarRatingDefaultExample({super.key});
@override
State<StarRatingDefaultExample> createState() =>
_StarRatingDefaultExampleState();
}
class _StarRatingDefaultExampleState extends State<StarRatingDefaultExample> {
double _value = 3;
@override
Widget build(BuildContext context) {
return StarRating(
value: _value,
onChanged: (v) => setState(() => _value = v),
);
}
}
class StarRatingChainExample extends StatefulComponent {
const StarRatingChainExample({super.key});
@override
State<StarRatingChainExample> createState() => _StarRatingChainExampleState();
}
class _StarRatingChainExampleState extends State<StarRatingChainExample> {
double _value = 3;
@override
Component build(BuildContext context) {
return StarRating(
value: _value,
onChanged: (v) => setState(() => _value = v),
)
.withStyle(
const CoreStarRatingStyle(
starSize: CoreSpace.space32,
starSpacing: CoreSpace.space12,
activeColor: CoreColor.token(CoreColors.warning),
),
)
.primary;
}
}
class StarRatingChainExample extends StatefulWidget {
const StarRatingChainExample({super.key});
@override
State<StarRatingChainExample> createState() => _StarRatingChainExampleState();
}
class _StarRatingChainExampleState extends State<StarRatingChainExample> {
double _value = 3;
@override
Widget build(BuildContext context) {
return StarRating(
value: _value,
onChanged: (v) => setState(() => _value = v),
)
.withStyle(
const CoreStarRatingStyle(
starSize: CoreSpace.space32,
starSpacing: CoreSpace.space12,
activeColor: CoreColor.token(CoreColors.warning),
),
)
.primary;
}
}
사용 시기 (When to Use)#
이 컴포넌트를 사용하세요:
- 상품, 서비스, 콘텐츠에 대한 사용자 만족도를 수집하는 경우
- 리뷰 섹션에서 평균 평점을 시각적으로 표시하는 경우
대신 다른 컴포넌트를 사용하세요:
Slider: 세밀한 수치 입력이 필요한 경우TextField: 정확한 숫자 값을 직접 입력받아야 하는 경우
기본 사용법 (Basic Usage)#
// 기본 별점 (읽기 전용)
StarRating(value: 3.5)
// 인터랙티브 별점
StarRating(
value: rating,
onChanged: (v) => setState(() => rating = v),
)
// 커스텀 별 모양 + 색 (색은 starRatingStyle 로)
StarRating(
value: 4,
starPoints: 6,
starInnerRadiusRatio: 0.5,
starRatingStyle: CoreStarRatingStyle(
activeColor: CoreColor.token(CoreColors.warning),
),
)
// 기본 별점 (읽기 전용)
StarRating(value: 3.5)
// 인터랙티브 별점
StarRating(
value: rating,
onChanged: (v) => setState(() => rating = v),
)
// 커스텀 별 모양 + 색 (색은 starRatingStyle 로)
StarRating(
value: 4,
starPoints: 6,
starInnerRadiusRatio: 0.5,
starRatingStyle: CoreStarRatingStyle(
activeColor: CoreColor.token(CoreColors.warning),
),
)
빠른 오버라이드 (Chain)#
이미 만든 StarRating 인스턴스에 스타일을 빠르게 덧붙이고 싶다면 withStyle 체인을 쓸 수 있습니다. 생성자의 style 슬롯 인자와 동일하게 동작하지만, 이미 구성된 위젯 위에서 바로 이어 쓸 수 있습니다.
.primary처럼 Core 토큰 상수 이름과 똑같은 이름의 getter도 있습니다 — withStyle을 한 번 더 줄인 sugar로, 이름이 곧 값이라(primary ==
CoreColors.primary) 어느 컴포넌트에서 써도 뜻이 갈리지 않으며, 위 예시처럼 withStyle 뒤에 이어붙일 수도 있습니다.
class StarRatingChainExample extends StatefulWidget {
const StarRatingChainExample({super.key});
@override
State<StarRatingChainExample> createState() => _StarRatingChainExampleState();
}
class _StarRatingChainExampleState extends State<StarRatingChainExample> {
double _value = 3;
@override
Widget build(BuildContext context) {
return StarRating(
value: _value,
onChanged: (v) => setState(() => _value = v),
)
.withStyle(
const CoreStarRatingStyle(
starSize: CoreSpace.space32,
starSpacing: CoreSpace.space12,
activeColor: CoreColor.token(CoreColors.warning),
),
)
.primary;
}
}
class StarRatingChainExample extends StatefulComponent {
const StarRatingChainExample({super.key});
@override
State<StarRatingChainExample> createState() => _StarRatingChainExampleState();
}
class _StarRatingChainExampleState extends State<StarRatingChainExample> {
double _value = 3;
@override
Component build(BuildContext context) {
return StarRating(
value: _value,
onChanged: (v) => setState(() => _value = v),
)
.withStyle(
const CoreStarRatingStyle(
starSize: CoreSpace.space32,
starSpacing: CoreSpace.space12,
activeColor: CoreColor.token(CoreColors.warning),
),
)
.primary;
}
}
Props / Parameters#
| 속성 | 타입 | 기본값 | 설명 |
|---|---|---|---|
value | double | 필수 | 현재 별점 값 |
max | double | 5.0 | 최대 별점 |
step | double | 0.5 | 별점 증가 단위 |
enabled | bool | true | 인터랙션 가능 여부 |
onChanged |
ValueChanged<double>? |
null |
별점 변경 콜백 |
starPoints |
double? |
null (→ 5) |
별 꼭짓점 수 |
starPointRounding |
double? |
null (→ 0.15) |
꼭짓점 둥글기 |
starValleyRounding |
double? |
null (→ 0) |
골짜기 둥글기 |
starSquash |
double? |
null (→ 0) |
수직 압축 |
starInnerRadiusRatio |
double? |
null (→ 0.4) |
안쪽/바깥 반지름 비율 |
starRotation |
double? |
null (→ 0) |
회전 (라디안) |
starRatingStyle |
CoreStarRatingStyle? |
null |
색 / 크기 / 간격 / 애니메이션 chrome 단일 진입점 |
direction |
CoreAxis |
CoreAxis.horizontal |
별이 놓이는 축. 별 하나가 채워지는 방향도 같이 결정합니다 — 가로는 왼쪽→오른쪽, 세로는 아래→위 |
name |
String? |
null |
숨은 native input 의 form 필드 이름 — Web 전용 |
Web 은 위 파라미터에 더해 id / classes / css / attributes 와 DOM 이벤트
슬롯(onClick / onKeyDown 등)을 받아 루트 요소로 통과시킵니다.
CoreStarRatingStyle 필드#
| 필드 | 타입 | 설명 |
|---|---|---|
animationDuration |
Duration? |
Size of each star icon (logical px). Fill-transition duration — how long the star fill sweeps when the rating value changes (Flutter value lerp / Web CSS width transition, same token on both platforms). |
starSize | double? | Star icon size (logical px). |
starSpacing |
double? |
Horizontal spacing between stars (logical px). |
activeColor |
CoreColor? |
Active (filled) star colour override. |
backgroundColor |
CoreColor? |
Inactive (empty) star background colour override. |
disabledActiveColor |
CoreColor? |
Active star colour override when disabled. null defers to [defaultDisabledActiveColor]. |
focusBorderColor |
CoreColor? |
Keyboard focus border colour override. null defers to [defaultFocusBorderColor]. |
focusBorderWidth |
double? |
Keyboard focus border width override (logical px, pre-scaling).
null
defers to [defaultFocusBorderWidth].
|
동작 스펙 (Behavior)#
인터랙션#
- 클릭/탭: 클릭한 위치의 별점으로 설정 (양 플랫폼)
- 호버: 마우스 위치에 따라 별점 미리보기 (양 플랫폼)
- 드래그 (Flutter): 드래그하면서 별점 실시간 변경
- 키보드 (Flutter): ← → 방향키로
step단위 증감 -
onChanged가null이거나enabled: false면 표시 전용이 되고, 포커스도 받지 않습니다.
반별 지원#
step: 0.5일 때 반별(half-star) 표시- 채워진 부분과 빈 부분의 경계를 clip으로 처리
축 (direction)#
direction 은 별이 놓이는 축과 별 하나가 채워지는 방향을 함께 정합니다.
CoreAxis.horizontal(기본): 별이 가로로 놓이고, 각 별은 왼쪽→오른쪽으로 채워집니다.-
CoreAxis.vertical: 별이 세로로 쌓이고, 각 별은 아래→위로 채워집니다 — 부분 채움이 옆으로 쓸리는 게 아니라 수위처럼 읽히도록.
포인터 진행 방향은 두 축 · 두 플랫폼 모두 가로 입니다. 세로 별점도 좌우로 드래그해 값을 바꿉니다.
사용 가이드라인 (Usage Guidelines)#
✅ Do#
색/크기/애니메이션은 starRatingStyle 하나로
StarRating(
value: rating,
onChanged: (v) => setState(() => rating = v),
starRatingStyle: CoreStarRatingStyle(
activeColor: CoreColor.token(CoreColors.warning),
),
)
색상·크기·간격·애니메이션은 전부 starRatingStyle 단일 슬롯으로 흐릅니다. 이 슬롯으로 override해야 프로젝트 테마와 같은 merge chain을 타 Flutter/Web 양쪽에서 일관되게 반영됩니다.
❌ Don't#
키보드만으로 값 조정이 가능하다고 가정하지 않기
// ❌ Web에서도 방향키로 값이 바뀔 거라 가정
StarRating(
value: rating,
onChanged: (v) => setState(() => rating = v),
)
Flutter는 포커스 상태에서 ←/→로 step 만큼 증감하지만, Web은 아직 화살표 키를 처리하지 않아 값 변경은 포인터로만 가능합니다. 키보드로도 조작 가능해야 한다면 별도의 대체 입력 수단을 함께 제공하세요.
접근성 (Accessibility)#
역할 / 시맨틱#
-
Web: 루트에
role="slider"+aria-label(활성 로케일의 별점 문구) +aria-valuenow/aria-valuemin(0) /aria-valuemax(max). -
Flutter:
Semantics(slider: true, label: <로케일 별점 문구>, value: '값 / max').
키보드#
-
Flutter:
FocusableActionDetector가←/→를 받아step만큼 값을 증감하고0..max로 clamp 합니다. -
Web: 인터랙티브할 때만
tabindex="0"이 붙어 포커스를 받고focus-visible:표시가 나타납니다. 화살표 키 처리는 아직 없습니다 — 값 변경은 포인터로만 가능합니다.
크로스 플랫폼 차이점 (Platform Differences)#
| 항목 | Flutter | Web |
|---|---|---|
| 별 렌더링 | StarBorder shape + ShaderMask 부분 채움 |
SVG path (CoreStarPath) |
| 포인터 | 클릭 + 호버 미리보기 + 드래그 | 클릭 + 호버 미리보기 |
| 키보드 | ← / → 로 step 증감 | 포커스만 (키 처리 없음) |
| 세로 축 채움 | LinearGradient 를 bottomCenter → topCenter 로 |
clip <rect> 를 아래 기준 scaleY 로 |
| form 연동 | 없음 | name 으로 숨은 native input 필드명 지정 |