image_picker, GestureDetector, Positioned를 활용하여 사진에 스티커를 붙이는 기능을 가진 Flutter APP를 만들어 보겠습니다.
이번 단계에서는 사진을 선택해서 배경 이미지를 적용하고 스티커 이미지를 선택할 수 있는 UI와 선택한 1개의 스티커를 배경 사진 위에 표시하는 것 까지 구현해 보기로 합니다.
구현
pubspec.yaml
...
dependencies:
flutter:
sdk: flutter
image_picker: ^1.0.7
...
# The following section is specific to Flutter packages.
flutter:
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true
# To add assets to your application, add an assets section, like this:
# assets:
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg
assets:
- assets/stickers/
main.dart
import 'dart:io'; // File 클래스를 사용하기 위해 필요
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: '스티커 앱',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const StickerEditorPage(),
);
}
}
class StickerEditorPage extends StatefulWidget {
const StickerEditorPage({super.key});
@override
State<StickerEditorPage> createState() => _StickerEditorPageState();
}
class _StickerEditorPageState extends State<StickerEditorPage> {
File? _selectedImage;
final ImagePicker _picker = ImagePicker();
// --- 스티커 관련 상태 변수 추가 ---
String? _selectedSticker; // 선택된 스티커의 경로 저장
final List<String> _stickerPaths = [ // 사용 가능한 스티커 목록
'assets/stickers/emoticon_1.png',
'assets/stickers/emoticon_2.png',
'assets/stickers/emoticon_3.png',
'assets/stickers/emoticon_4.png',
'assets/stickers/emoticon_5.png',
'assets/stickers/emoticon_6.png',
'assets/stickers/emoticon_7.png',
// 필요에 따라 더 많은 스티커 경로 추가
];
// ------------------------------------
Future<void> _pickImageFromGallery() async {
final XFile? pickedFile = await _picker.pickImage(source: ImageSource.gallery);
if (pickedFile != null) {
setState(() {
_selectedImage = File(pickedFile.path);
_selectedSticker = null; // 새 이미지 선택 시 스티커 선택 초기화
});
}
}
// --- 스티커 선택 함수 추가 ---
void _selectSticker(String stickerPath) {
setState(() {
_selectedSticker = stickerPath;
});
}
// ---------------------------
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('스티커 붙이기'),
),
body: Column( // 전체 레이아웃을 Column으로 변경
children: <Widget>[
// 1. 이미지 및 스티커 표시 영역 (Expanded 사용)
Expanded(
child: Center(
child: _selectedImage == null
? const Text('사진을 선택해주세요.')
: Stack( // 이미지 위에 스티커를 올리기 위해 Stack 위젯 사용
alignment: Alignment.center, // Stack 내 자식들 중앙 정렬
children: <Widget>[
Image.file(_selectedImage!),
if (_selectedSticker != null)
Positioned( // 스티커 위치를 정밀하게 제어 (여기서는 중앙)
// 이 부분을 GestureDetector로 감싸서 드래그 기능 추가 가능
child: Image.asset(
_selectedSticker!,
width: 100, // 스티커 크기 조절
height: 100,
),
),
],
),
),
),
// 2. 스티커 선택 UI (화면 하단에 표시)
if (_selectedImage != null) // 이미지가 선택된 경우에만 스티커 목록 표시
Container(
height: 120, // 스티커 목록의 높이
padding: const EdgeInsets.symmetric(vertical: 8.0),
color: Colors.grey[200],
child: ListView.builder(
scrollDirection: Axis.horizontal, // 가로 스크롤
itemCount: _stickerPaths.length,
itemBuilder: (context, index) {
final stickerPath = _stickerPaths[index];
return GestureDetector(
onTap: () => _selectSticker(stickerPath),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: Container(
decoration: BoxDecoration(
border: _selectedSticker == stickerPath
? Border.all(color: Colors.blue, width: 2) // 선택된 스티커 강조
: null,
borderRadius: BorderRadius.circular(8),
),
child: Image.asset(
stickerPath,
width: 80,
height: 80,
fit: BoxFit.contain,
),
),
),
);
},
),
),
// 3. 사진 선택 버튼
Padding(
padding: const EdgeInsets.all(16.0),
child: ElevatedButton(
onPressed: _pickImageFromGallery,
child: Text(_selectedImage == null ? '사진 선택하기' : '다른 사진 선택'),
),
),
],
),
);
}
}
image_picker 패키지
ImagePicker 클래스를 사용하여 갤러리(ImageSource.gallery) 또는 카메라(ImageSource.camera)에서 이미지를 가져올 수 있습니다.
pickImage() 메서드는 XFile 객체를 반환하며, 이를 File 객체로 변환하여 사용합니다.
_selectedImage 변수
사용자가 선택한 이미지 파일을 저장합니다. File? 타입으로, 처음에는 null 값을 가집니다.
_pickImageFromGallery() 함수
ImagePicker를 사용하여 갤러리에서 이미지를 선택합니다.
이미지가 성공적으로 선택되면 setState를 호출하여 UI를 업데이트하고 _selectedImage에 선택된 이미지 파일을 할당합니다.
build() 메서드
_selectedImage가 null이 아니면 Image.file() 위젯을 사용하여 선택된 이미지를 화면에 표시합니다.
“사진 선택하기” 버튼을 누르면 _pickImageFromGallery() 함수가 호출됩니다
Reference
https://heavenly.tistory.com/entry/Flutter-기본-기능-as-show-hide-변수나-함수-클래스명이-같은-경우-해결-방법-example
“Flutter Example : Photo Sticker – Step 1”에 대한 1개의 생각