Carousel#
슬라이드 형태로 콘텐츠를 순환하며 보여주는 컴포넌트입니다. 자동 재생, 탐색 버튼, 인디케이터를 지원합니다.
Live Preview#
class CarouselDefaultExample extends StatefulComponent {
const CarouselDefaultExample({super.key});
@override
State<CarouselDefaultExample> createState() =>
_CarouselDefaultExampleState();
}
class _CarouselDefaultExampleState extends State<CarouselDefaultExample> {
int _index = 0;
@override
Component build(BuildContext context) {
return Carousel(
currentIndex: _index,
onIndexChanged: (idx) => setState(() => _index = idx),
items: [
div(
[Component.text('Slide 1')],
styles: Styles(raw: {
'background': '#3B82F6',
'color': 'white',
'font-size': '18px',
'display': 'flex',
'align-items': 'center',
'justify-content': 'center',
'padding': 'var(--coui-space-64)',
}),
),
div(
[Component.text('Slide 2')],
styles: Styles(raw: {
'background': '#22C55E',
'color': 'white',
'font-size': '18px',
'display': 'flex',
'align-items': 'center',
'justify-content': 'center',
'padding': 'var(--coui-space-64)',
}),
),
div(
[Component.text('Slide 3')],
styles: Styles(raw: {
'background': '#F97316',
'color': 'white',
'font-size': '18px',
'display': 'flex',
'align-items': 'center',
'justify-content': 'center',
'padding': 'var(--coui-space-64)',
}),
),
],
);
}
}
class CarouselDefaultExample extends StatefulWidget {
const CarouselDefaultExample({super.key});
@override
State<CarouselDefaultExample> createState() =>
_CarouselDefaultExampleState();
}
class _CarouselDefaultExampleState extends State<CarouselDefaultExample> {
@override
Widget build(BuildContext context) {
return Carousel(
transition: CarouselTransition.sliding(),
items: [
Container(
alignment: Alignment.center,
color: const Color(0xFF3B82F6),
padding: const EdgeInsets.all(CoreSpace.space64),
child: const Text('Slide 1',
style: TextStyle(color: Colors.white, fontSize: 18)),
),
Container(
alignment: Alignment.center,
color: const Color(0xFF22C55E),
padding: const EdgeInsets.all(CoreSpace.space64),
child: const Text('Slide 2',
style: TextStyle(color: Colors.white, fontSize: 18)),
),
Container(
alignment: Alignment.center,
color: const Color(0xFFF97316),
padding: const EdgeInsets.all(CoreSpace.space64),
child: const Text('Slide 3',
style: TextStyle(color: Colors.white, fontSize: 18)),
),
],
);
}
}
사용 시기 (When to Use)#
이 컴포넌트를 사용하세요:
- 여러 이미지나 콘텐츠를 슬라이드쇼로 표시할 때
- 프로모션 배너를 순환 표시할 때
대신 다른 컴포넌트를 사용하세요:
HoverGallery: 호버 기반 이미지 전환
기본 사용법 (Basic Usage)#
Carousel(
transition: CarouselTransition.sliding(),
items: [
Container(color: Colors.blue, child: Text('Slide 1')),
Container(color: Colors.green, child: Text('Slide 2')),
Container(color: Colors.orange, child: Text('Slide 3')),
],
autoPlay: true,
showIndicators: true,
showNavigation: true,
)
Carousel(
currentIndex: _index,
onIndexChanged: (i) => setState(() => _index = i),
items: [
div([Component.text('Slide 1')]),
div([Component.text('Slide 2')]),
div([Component.text('Slide 3')]),
],
autoPlay: true,
showIndicators: true,
showNavigation: true,
)
Props / Parameters#
| 속성 | 타입 | 기본값 | 설명 |
|---|---|---|---|
items |
List<Widget/Component>? |
null |
슬라이드 목록 (통일 cross-platform API) |
itemCount | int? | null | 아이템 수 |
duration |
Duration? |
null |
자동 재생 간격 |
autoPlay | bool | false | 자동 재생 |
showIndicators |
bool |
true |
인디케이터 표시 |
showNavigation |
bool |
true |
좌우 버튼 표시 |
currentIndex |
int |
0 |
현재 슬라이드 인덱스 |
onIndexChanged |
Function(int)? |
null |
인덱스 변경 콜백 |
wrap | bool | true | 무한 순환 |
pauseOnHover |
bool |
true |
호버 시 자동 재생 일시 정지 |
carouselStyle |
CoreCarouselStyle? |
null |
인스턴스 스타일 (Style 시스템 참조) |
itemBuilder (lazy 빌더) · transition (전환 효과) · controller · sizeConstraint
는 Flutter 전용 power-user API 로, 통일 contract 멤버가 아닌 Flutter 위젯 필드입니다 (verify.md 7-7 — 단일 <W>
generic). 통일 cross-platform 경로는 items 리스트입니다.
스타일 시스템 (Style System)#
Carousel 의 모든 chrome / dimensional / nested-slot 오버라이드는 CoreCarouselStyle 단일 슬롯으로 흐릅니다 (Epic #1302 원칙 6/7/8, Phase 6f 팬텀 generic 제거). behaviour (autoPlay
/ wrap / pauseOnHover / showIndicators / showNavigation) 는 위젯 파라미터로 직접 전달합니다.
시맨틱 vs 스타일#
-
behaviour: 위젯 파라미터로 직접 (
autoPlay,wrap,pauseOnHover,showIndicators,showNavigation,currentIndex,onIndexChanged) -
chrome / dimensional / 슬롯 스타일:
CoreCarouselStyle한 곳으로 (indicatorActiveColor/indicatorInactiveColor/indicatorSize/indicatorSpacing/controlOverlayColor/prevNextButtonStyle)
Resolve chain#
design system default for carousel
→ CoreCarouselTheme.style // 프로젝트 공통
→ parent component slot override
→ widget.carouselStyle // 인스턴스별
각 nested 슬롯 스타일 (prevNextButtonStyle) 은 자기 컴포넌트의 자체 resolve chain 으로 다시 한 번 머지됩니다.
슬롯 매핑 (CoreCarouselStyle 6 필드)#
| 필드 | 타입 (Flutter) | 적용 영역 |
|---|---|---|
indicatorActiveColor | CoreColor? | 활성 인디케이터 dot 색 |
indicatorInactiveColor | CoreColor? | 비활성 인디케이터 dot 색 |
indicatorSize | double? | 인디케이터 dot 지름 (px) |
indicatorSpacing |
double? |
인디케이터 dot 간 native Row.spacing (px) |
controlOverlayColor |
CoreColor? |
prev/next 버튼 배경 오버레이 |
prevNextButtonStyle |
CoreButtonStyle? |
prev/next 버튼 chrome (Button 슬롯으로 위임) |
동작 스펙 (Behavior)#
- 좌우 버튼으로 슬라이드 전환
- 인디케이터 dot 클릭으로 직접 이동
autoPlay: true시 자동 순환pauseOnHover: true시 호버 시 일시 정지wrap: true시 마지막에서 첫 번째로 순환
크로스 플랫폼 차이점 (Platform Differences)#
| 항목 | Flutter | Web |
|---|---|---|
| 클래스명 | Carousel | Carousel |
| 전환 | CarouselTransition (sliding/fading) |
CSS translateX + transition (sliding) |
| 드래그 | GestureDetector 지원 |
mousedown/mousemove/mouseup 지원 |
| 자동 재생 | Ticker 기반 | Timer.periodic 기반 |
| 호버 감지 | MouseRegion |
mouseenter/mouseleave |
| 무한 순환 | CarouselController 연속 값 | 가상 무한 트랙 (clone + instant jump) |
관련 컴포넌트 (Related Components)#
- HoverGallery: 호버 기반 이미지 전환
- DotIndicator: 페이지 위치 표시