StackLayout#
CoStackLayout 은 자식 위젯을 z 축으로 겹쳐 그리는 레이아웃 primitive 입니다.
Flutter 의 Stack 과 시맨틱이 1:1 동일하며 (fit / alignment
/ clipBehavior /
textDirection), 자식 중 CoPositioned 인 항목은 top
/ right / bottom /
left / width / height 로 절대 좌표 배치됩니다 — Flutter
Positioned 와 동등.
카드 덱 같은 누적 겹침 효과는 자식들을 모두 CoPositioned 로 감싸 top: i * offset
형태로 누적 좌표를 직접 지정해서 만듭니다.
Live Preview#
class StackLayoutDefaultExample extends StatelessComponent {
const StackLayoutDefaultExample({super.key});
static const _kLabels = ['Layer 1', 'Layer 2', 'Layer 3'];
static const _kPerLayerOffset = CoreSpace.space8;
@override
Component build(BuildContext context) {
final cs = context.theme.colorScheme;
final ts = context.theme.typography;
final layerClasses =
'w-${CoreSpace.scale.space160} h-${CoreSpace.scale.space80} '
'flex items-center justify-center '
'bg-${cs.surfaceContainer} border border-${cs.outline} '
'rounded-${CoreRadius.scale.radius16} '
'text-${ts.bodyMedium} text-${cs.onSurface}';
final totalHeight =
CoreSpace.space80 + (_kLabels.length - 1) * _kPerLayerOffset;
return div(
[
CoStacks(
children: [
for (var i = 0; i < _kLabels.length; i++)
CoPosition(
top: i * _kPerLayerOffset,
child: div(
[Component.text(_kLabels[i])],
classes: layerClasses,
),
),
],
),
],
styles: Styles(
raw: {
'width': '${CoreSpace.space160 / 16}rem',
'height': '${totalHeight / 16}rem',
},
),
);
}
}
class StackLayoutDefaultExample extends StatelessWidget {
const StackLayoutDefaultExample({super.key});
static const _kLabels = ['Layer 1', 'Layer 2', 'Layer 3'];
static const _kPerLayerOffset = CoreSpace.space8;
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final totalHeight =
CoreSpace.space80 + (_kLabels.length - 1) * _kPerLayerOffset;
return SizedBox(
width: CoreSpace.space160,
height: totalHeight,
child: CoStacks(
children: [
for (var i = 0; i < _kLabels.length; i++)
CoPosition(
top: i * _kPerLayerOffset,
child: Container(
width: CoreSpace.space160,
height: CoreSpace.space80,
alignment: Alignment.center,
decoration: BoxDecoration(
color: theme.colorScheme.surfaceContainer,
borderRadius: BorderRadius.circular(CoreRadius.radius16),
border: Border.all(color: theme.colorScheme.outline!),
),
child: Text(
_kLabels[i],
style: theme.typography.bodyMedium.copyWith(
color: theme.colorScheme.onSurface,
),
),
),
),
],
),
);
}
}
사용 시기 (When to Use)#
이 컴포넌트를 사용하세요:
- 자식을 z 축으로 겹쳐야 할 때 (배지, 오버레이, 카드 덱)
-
Flutter
Stack/ Webposition: absolute의 양쪽 동일한 시맨틱 이 필요할 때 CoPositioned로 자식의 절대 좌표를 명시하고 싶을 때
대신 다른 컴포넌트를 사용하세요:
Group: 자식을 행/열 방향으로 단순 정렬하고 싶을 때Resizable: 분할 가능한 좌우/상하 영역이 필요할 때
기본 사용법 (Basic Usage)#
// 카드 덱 — 자식들을 모두 CoPositioned 로 감싸 누적 좌표 지정
CoStackLayout(
children: [
for (var i = 0; i < labels.length; i++)
CoPositioned(
top: i * 8.0,
child: Card(child: Text(labels[i])),
),
],
)
// 일반 z 스택 — non-positioned 자식 + 우상단 배지
CoStackLayout(
children: [
background,
CoPositioned(top: 8, right: 8, child: badge),
],
)
Web 에서도 동일한 생성자로 사용합니다 — children: List<Component> 만 다릅니다.
Props / Parameters#
CoStackLayout#
| 이름 | 타입 | 기본값 | 설명 |
|---|---|---|---|
children |
List<W> |
required | 자식 목록. 마지막 자식이 최상단 |
alignment |
CoreAlignment |
topStart |
non-positioned 자식의 정렬 |
fit |
CoreStackFit |
loose |
부모 constraint 전달 정책 (loose / expand / passthrough) |
clipBehavior |
CoreClipBehavior |
hardEdge |
overflow 클립 정책 (
none
/
hardEdge
/
antiAlias
/
antiAliasWithSaveLayer
)
|
textDirection |
CoreTextDirection? |
null |
start/end 정렬을 ltr/rtl 로 해석할 방향 |
CoPositioned#
| 이름 | 타입 | 기본값 | 설명 |
|---|---|---|---|
child | W? | null | 위치 지정할 자식 |
top / right / bottom / left |
double? |
null |
스택 박스 가장자리에서의 거리 (logical px) |
width / height |
double? |
null |
자식의 명시 크기 (logical px) |
CoPositioned.fill({ ... }) 편의 생성자는 top/right/bottom/left = 0 으로
자식이 스택 전체를 채우게 합니다 (Flutter Positioned.fill 매핑).
Theming#
CoreComponentTheme.stackLayout 에서 기본값 오버라이드:
CoreComponentTheme(
stackLayout: CoreStackLayoutTheme(
alignment: CoreAlignment.topStart,
fit: CoreStackFit.loose,
clipBehavior: CoreClipBehavior.hardEdge,
),
)