Avatar#
사용자 프로필 이미지 또는 이니셜을 표시하는 아바타 컴포넌트입니다.
Live Preview#
class AvatarDefaultExample extends StatefulComponent {
const AvatarDefaultExample({super.key});
@override
State<AvatarDefaultExample> createState() => _AvatarDefaultExampleState();
}
class _AvatarDefaultExampleState extends State<AvatarDefaultExample> {
@override
Component build(BuildContext context) {
return CoAvatar(
initials: 'AB',
);
}
}
class AvatarDefaultExample extends StatefulWidget {
const AvatarDefaultExample({super.key});
@override
State<AvatarDefaultExample> createState() => _AvatarDefaultExampleState();
}
class _AvatarDefaultExampleState extends State<AvatarDefaultExample> {
@override
Widget build(BuildContext context) {
return const CoAvatar(
initials: 'AB',
);
}
}
사용 시기 (When to Use)#
이 컴포넌트를 사용하세요:
- 사용자 프로필 이미지 또는 이니셜을 표시할 때
- 댓글, 채팅, 팀 멤버 목록에서 사용자를 시각적으로 식별할 때
- 온라인/오프라인 상태를 함께 표시해야 할 때
대신 다른 컴포넌트를 사용하세요:
Icon: 사용자가 아닌 일반 아이콘을 표시할 때Badge: 텍스트 레이블이 필요한 상태 표시일 때Image: 프로필이 아닌 일반 이미지를 표시할 때
기본 사용법 (Basic Usage)#
// 이미지 아바타
CoAvatar(
imageUrl: 'https://example.com/photo.jpg',
size: CoreComponentSize.md,
)
// 이니셜 아바타
CoAvatar(
initials: '홍',
size: CoreComponentSize.lg,
)
// 링 효과
CoAvatar(
imageUrl: user.photoUrl,
ring: true,
)
// 커스텀 child
CoAvatar(
size: CoreComponentSize.sm,
child: Icon(Icons.person),
)
// 이미지 아바타
CoAvatar(
imageUrl: 'https://example.com/photo.jpg',
size: CoreComponentSize.md,
)
// 이니셜 아바타
CoAvatar(
initials: '홍',
size: CoreComponentSize.lg,
)
// 링 효과
CoAvatar(
imageUrl: 'https://example.com/photo.jpg',
size: CoreComponentSize.md,
ring: true,
)
// 커스텀 child
CoAvatar(
size: CoreComponentSize.sm,
child: text('JD'),
)
Props / Parameters#
| 속성 | 타입 | 기본값 | 설명 |
|---|---|---|---|
imageUrl |
String? |
null |
프로필 이미지 URL |
initials |
String? |
null |
이니셜 텍스트 |
size |
CoreComponentSize |
md |
아바타 크기 |
ring | bool | false | 링 보더 표시 여부 |
backgroundColor |
Color? / CoreColor? |
null |
배경색 (legacy — avatarStyle.backgroundColor 권장) |
child |
Widget? |
null |
커스텀 내용 (imageUrl/initials 대체) |
badge |
Widget? / Component? |
null |
아바타 위에 오버레이 되는 배지 |
badgeAlignment |
AlignmentGeometry? / Object? |
null |
배지 정렬 |
badgeGap |
double? |
null |
배지와 아바타 사이 갭 |
avatarStyle |
CoreAvatarStyle<Color>? / CoreAvatarStyle<CoreColor>? |
null |
인스턴스 스타일 (Style 시스템 참조) |
스타일 시스템 (Style System)#
Avatar 의 모든 chrome / dimensional / nested-slot 오버라이드는 CoreAvatarStyle<Clr> 단일 슬롯으로 흐릅니다 (Epic #1302 원칙 6/7/8). 시맨틱 enum (size) 과 behaviour (ring
/ badge / imageUrl / initials) 는 위젯 파라미터로 직접 전달합니다.
시맨틱 vs 스타일#
-
시맨틱 enum / behaviour: 위젯 파라미터로 직접 (
size,ring,imageUrl,initials,child,badge,badgeAlignment,badgeGap) -
chrome / dimensional / 슬롯 스타일:
CoreAvatarStyle한 곳으로 (backgroundColor/foregroundColor/borderRadius/ringColor/ringWidth/fallbackTextStyle)
Resolve chain#
design system default for avatar
→ CoreAvatarTheme.style // 프로젝트 공통
→ parent component slot override
→ widget.avatarStyle // 인스턴스별
fallbackTextStyle 슬롯은 자기 컴포넌트의 자체 resolve chain 으로 다시 한 번 머지됩니다.
슬롯 매핑 (CoreAvatarStyle 6 필드)#
| 필드 | 타입 (Flutter) | 적용 영역 |
|---|---|---|
backgroundColor |
Color? |
아바타 배경 (legacy backgroundColor prop 보다 우선 적용) |
foregroundColor | Color? | 이니셜 폴백 텍스트 색 |
borderRadius |
double? |
모서리 반지름 (px). null → 원형 (shape: circle) |
ringColor | Color? | ring: true 일 때 링 색 |
ringWidth |
double? |
ring: true 일 때 링 두께 (px) |
fallbackTextStyle |
CoreTextStyle<Color>? |
이니셜 폴백 텍스트 스타일 (이미지 / 자식 없을 때 표시) |
Migration — 옛 평면 chrome → 새 위치 매핑#
| 옛 위치 (legacy) | 새 위치 |
|---|---|
backgroundColor 위젯 prop |
avatarStyle.backgroundColor
(인스턴스) 또는
CoreAvatarTheme.style.backgroundColor
(프로젝트)
|
| 인스턴스 ring 색상 (불가능) | avatarStyle.ringColor |
| 인스턴스 ring 두께 (불가능) | avatarStyle.ringWidth |
| 인스턴스 모서리 반지름 (불가능 — 항상 circle) | avatarStyle.borderRadius |
| 인스턴스 이니셜 폴백 텍스트 스타일 (불가능) | avatarStyle.fallbackTextStyle |
backgroundColor prop 은 호환을 위해 유지되지만 새 코드에서는 avatarStyle.backgroundColor 사용을 권장합니다.
사용 예 (Flutter)#
CoAvatar(
initials: 'JD',
ring: true,
avatarStyle: CoreAvatarStyle(
backgroundColor: Color(0xFF3B82F6),
foregroundColor: Colors.white,
ringColor: Color(0xFFE11D48),
ringWidth: 3,
fallbackTextStyle: CoreTextStyle(fontWeight: 700),
),
)
사용 예 (Web)#
CoAvatar(
initials: 'JD',
ring: true,
avatarStyle: CoreAvatarStyle<CoreColor>(
backgroundColor: CoreColor.fromHex('#3B82F6'),
fallbackTextStyle: CoreTextStyle<CoreColor>(fontWeight: 700),
),
)
변형 (Variants)#
크기#
| 크기 | 값 | 픽셀 |
|---|---|---|
| XS | CoreComponentSize.xs | 24px |
| SM | CoreComponentSize.sm | 32px |
| MD | CoreComponentSize.md | 40px |
| LG | CoreComponentSize.lg | 48px |
| XL | CoreComponentSize.xl | 64px |
링 효과#
CoAvatar(imageUrl: url, ring: true)
CoAvatar(imageUrl: url, ring: false)
배경색 커스텀#
CoAvatar(initials: 'AB', backgroundColor: Colors.blue)
CoAvatar(initials: 'CD', backgroundColor: Colors.green)
동작 스펙 (Behavior)#
이미지 로딩#
ImageProvider(Flutter) 또는<img>태그(Web)로 이미지 표시- 이미지 로드 실패 시 자동으로
initials텍스트로 폴백 -
Flutter:
Avatar.network()생성자에서cacheWidth/cacheHeight로 메모리 최적화 - Web:
<img>태그에alt속성 자동 적용
Ring 효과#
- Flutter: 2px gap + 1px stroke,
ring: true로 활성화 -
Web: CSS
ring-2 ring-primary ring-offset-2클래스,ring: true로 활성화
CoAvatar(
imageUrl: 'https://example.com/photo.jpg',
ring: true,
)
이미지 폴백#
imageUrl과initials를 함께 제공하면 이미지 로드 실패 시 이니셜로 폴백child가 있으면 imageUrl/initials보다 우선
CoAvatar(
imageUrl: 'https://example.com/photo.jpg',
initials: 'JD',
size: CoreComponentSize.md,
)
사용 가이드라인 (Usage Guidelines)#
✅ Do#
이미지와 이니셜 폴백을 항상 함께 제공하세요.
CoAvatar(
imageUrl: user.photoUrl,
initials: 'JD',
)
이미지 로드 실패 시 이니셜이 표시되어 사용자를 식별할 수 있습니다.
❌ Don't#
이미지 없이 빈 아바타를 표시하지 마세요.
이니셜이나 기본 아이콘 없는 빈 원형은 사용자를 식별할 수 없습니다.
✅ Do#
그룹에서 maxCount를 설정하세요.
Row(
children: teamMembers.take(5).map((m) => CoAvatar(
imageUrl: m.photo,
size: CoreComponentSize.sm,
)).toList(),
)
많은 아바타가 나열되면 레이아웃이 깨집니다. 3~5개가 적절합니다.
❌ Don't#
아바타 크기를 컨텍스트에 맞지 않게 사용하지 마세요.
댓글 목록에 XL(72px) 아바타를 사용하면 콘텐츠보다 아바타가 강조됩니다. 인라인에는 SM(32px), 프로필 헤더에는 LG(56px) 이상을 사용하세요.
✅ Do#
상태 표시는 실시간 정보에만 사용하세요.
CoAvatar(
imageUrl: user.photoUrl,
ring: user.isOnline,
)
온라인/오프라인 같은 실시간 상태만 뱃지로 표시합니다.
❌ Don't#
정적 역할 정보를 아바타 뱃지로 표시하지 마세요.
"관리자", "멤버" 같은 역할은 별도 텍스트 레이블로 표시하세요.
접근성 (Accessibility)#
스크린 리더#
- Flutter: 이미지 아바타에 사용자 이름 시맨틱 제공. 이니셜 텍스트가 읽힘
- Web:
<img>태그의alt속성으로 사용자 이름 전달. 폴백은 텍스트가 직접 읽힘
최소 크기#
- 인터랙티브 아바타(클릭 가능): 최소 44×44dp 터치 영역 확보
- XS(24px) 아바타는 표시 전용으로만 사용
색상 대비#
- 이니셜 텍스트와 배경색의 대비 WCAG AA 준수
- Ring 효과는 색상 이외의 시각적 구분(간격)도 제공
크로스 플랫폼 차이점 (Platform Differences)#
| 항목 | Flutter | Web |
|---|---|---|
| 크기 시스템 | 연속적 double (기본 40px) | AvatarSize enum (xs~xl) |
| 이미지 | ImageProvider 추상화 |
<img> 태그 src |
| 폴백 | 자동 이니셜 표시 | fallback prop |
| 뱃지 | AvatarBadge 위젯 (색상, 크기, 커스텀) | 미지원 |
| Ring | ring: Color (2px gap + 1px stroke) |
ring: bool (CSS ring 클래스) |
| 그룹 오버랩 | CustomClipper 8방향 | CSS -space-x-4 2방향 |
| 그룹 maxCount | 미지원 (수동 구현) | max: int + "+N" 뱃지 |
| 테마 | AvatarTheme (size, borderRadius, textStyle) |
Tailwind CSS 클래스 |
| 이니셜 추출 | Avatar.getInitials() | Avatar.getInitials() |
관련 컴포넌트 (Related Components)#
- Badge: 상태 텍스트 레이블. Avatar의 badge 대신 텍스트 기반 상태 표시
- Icon: 아이콘 시스템. Avatar의 커스텀 child로 아이콘 배치 가능
- HoverCard: 호버 미리보기. Avatar에 호버하면 프로필 카드 표시
조합 예제#
// 댓글 목록 패턴
ListView.builder(
itemBuilder: (context, index) {
final comment = comments[index];
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
HoverCard(
hoverBuilder: (context) => UserProfileCard(user: comment.author),
child: Avatar(
imageUrl: comment.author.photoUrl,
initials: Avatar.getInitials(comment.author.name),
size: AvatarSize.sm,
status: comment.author.isOnline
? AvatarStatus.online
: null,
),
),
SizedBox(width: 12),
Expanded(child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(comment.author.name,
style: TextStyle(fontWeight: FontWeight.bold)),
Text(comment.body),
],
)),
],
);
},
)