이미지와 아이콘 — Asset 관리부터 CachedNetworkImage까지
이미지와 아이콘 — Asset 관리부터 CachedNetworkImage까지
앱에서 이미지는 필수 요소입니다. Flutter에서 로컬 에셋 이미지, 네트워크 이미지, 아이콘을 다루는 방법과 성능 최적화를 정리해보겠습니다.
로컬 에셋 이미지
에셋 등록
# pubspec.yaml
flutter:
assets:
- assets/images/ # 폴더 전체 등록
- assets/images/logo.png # 개별 파일 등록
프로젝트 루트에 assets/images/ 폴더를 만들고 이미지를 넣으면 됩니다.
해상도별 이미지 제공
assets/
images/
logo.png # 1x (기본)
2.0x/
logo.png # 2x
3.0x/
logo.png # 3x
Flutter가 디바이스 해상도에 맞는 이미지를 자동으로 선택합니다.
사용
// 기본 사용
Image.asset('assets/images/logo.png')
// 크기 지정
Image.asset(
'assets/images/logo.png',
width: 200,
height: 100,
fit: BoxFit.contain,
)
네트워크 이미지
// 기본 네트워크 이미지
Image.network(
'https://example.com/photo.jpg',
width: 300,
height: 200,
fit: BoxFit.cover,
// 로딩 중 표시
loadingBuilder: (context, child, loadingProgress) {
if (loadingProgress == null) return child;
return Center(
child: CircularProgressIndicator(
value: loadingProgress.expectedTotalBytes != null
? loadingProgress.cumulativeBytesLoaded /
loadingProgress.expectedTotalBytes!
: null,
),
);
},
// 에러 시 표시
errorBuilder: (context, error, stackTrace) {
return const Icon(Icons.error, size: 48);
},
)
BoxFit 옵션
| 값 | 설명 |
|---|---|
BoxFit.contain | 비율 유지, 전체가 보이도록 |
BoxFit.cover | 비율 유지, 영역을 꽉 채움 (잘릴 수 있음) |
BoxFit.fill | 비율 무시, 영역에 맞게 늘림 |
BoxFit.fitWidth | 너비에 맞춤 |
BoxFit.fitHeight | 높이에 맞춤 |
BoxFit.none | 원본 크기 그대로 |
BoxFit.scaleDown | contain과 비슷, 축소만 함 |
실무에서는 프로필 사진에 cover, 로고에 contain을 가장 많이 씁니다.
CachedNetworkImage — 캐싱 적용
네트워크 이미지를 매번 다운로드하면 비효율적입니다. cached_network_image 패키지로 디스크 캐싱을 적용하세요.
# pubspec.yaml
dependencies:
cached_network_image: ^3.3.0
import 'package:cached_network_image/cached_network_image.dart';
CachedNetworkImage(
imageUrl: 'https://example.com/photo.jpg',
width: 300,
height: 200,
fit: BoxFit.cover,
// 로딩 중 플레이스홀더
placeholder: (context, url) => const Center(
child: CircularProgressIndicator(),
),
// 에러 시
errorWidget: (context, url, error) => const Icon(Icons.error),
// 캐시 기간 설정 (기본 30일)
cacheManager: CacheManager(
Config(
'customCacheKey',
stalePeriod: const Duration(days: 7),
),
),
)
ClipRRect — 둥근 모서리 이미지
// 둥근 모서리
ClipRRect(
borderRadius: BorderRadius.circular(12),
child: Image.network(
'https://example.com/photo.jpg',
width: 200,
height: 200,
fit: BoxFit.cover,
),
)
// 원형 이미지
ClipOval(
child: Image.network(
'https://example.com/avatar.jpg',
width: 80,
height: 80,
fit: BoxFit.cover,
),
)
// CircleAvatar (프로필 이미지에 최적)
CircleAvatar(
radius: 40,
backgroundImage: NetworkImage('https://example.com/avatar.jpg'),
// 로딩/에러 시 대체
child: const Icon(Icons.person),
)
아이콘
Material Icons
// 기본 아이콘
Icon(
Icons.favorite,
color: Colors.red,
size: 32,
)
// 아이콘 버튼
IconButton(
icon: const Icon(Icons.share),
onPressed: () {},
tooltip: '공유하기',
)
커스텀 아이콘 (SVG)
# pubspec.yaml
dependencies:
flutter_svg: ^2.0.0
import 'package:flutter_svg/flutter_svg.dart';
// SVG 에셋 표시
SvgPicture.asset(
'assets/icons/custom_icon.svg',
width: 32,
height: 32,
colorFilter: const ColorFilter.mode(
Colors.blue,
BlendMode.srcIn,
),
)
// SVG 네트워크 이미지
SvgPicture.network(
'https://example.com/icon.svg',
width: 32,
height: 32,
)
DecorationImage — Container 배경 이미지
Container(
width: double.infinity,
height: 200,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
image: const DecorationImage(
image: AssetImage('assets/images/background.jpg'),
fit: BoxFit.cover,
// 어둡게 오버레이
colorFilter: ColorFilter.mode(
Colors.black45,
BlendMode.darken,
),
),
),
child: const Center(
child: Text(
'배경 이미지 위의 텍스트',
style: TextStyle(
color: Colors.white,
fontSize: 24,
fontWeight: FontWeight.bold,
),
),
),
)
FadeInImage — 로딩 전환 효과
FadeInImage(
placeholder: const AssetImage('assets/images/placeholder.png'),
image: const NetworkImage('https://example.com/photo.jpg'),
fadeInDuration: const Duration(milliseconds: 300),
fit: BoxFit.cover,
width: 300,
height: 200,
)
// 메모리 플레이스홀더 (투명 이미지)
FadeInImage.memoryNetwork(
placeholder: kTransparentImage,
image: 'https://example.com/photo.jpg',
fit: BoxFit.cover,
)
정리
- 로컬 이미지는
pubspec.yaml에 에셋 등록 후Image.asset()사용 - 해상도별 이미지(1x, 2x, 3x)를 제공하면 Flutter가 자동 선택합니다
- 네트워크 이미지는
cached_network_image로 캐싱하세요 - 프로필 이미지에는
CircleAvatar, 둥근 모서리에는ClipRRect - SVG는
flutter_svg패키지로 처리합니다 BoxFit.cover와BoxFit.contain의 차이를 이해하고 용도에 맞게 사용하세요
댓글 로딩 중...