반응형
Image picker 라이브러리를 추가해준다. 링크
flutter pub add image_picker
iOS 에뮬레이터의 경우 카메라 기능을 사용할 수 없다.
그리고 iOS의 경우 <project root>/ios/Runner/Info.plist 파일에 내용을 추가하여 권한 설정을 해주어야한다.
<key>NSCameraUsageDescription</key>
<string>카메라 사용에 필요합니다.</string>
<key>NSMicrophoneUsageDescription</key>
<string>마이크 사용에 필요합니다.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>사진라이브러리 사용에 필요합니다.</string>
아래는 전체 파일의 내용
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>Youtube Camera</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>youtube_camera</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSCameraUsageDescription</key>
<string>카메라 사용에 필요합니다.</string>
<key>NSMicrophoneUsageDescription</key>
<string>마이크 사용에 필요합니다.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>사진라이브러리 사용에 필요합니다.</string>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
</dict>
</plist>
안드로이드의 경우 따로 설정해줄 필요는 없습니다.
먼저 기본 화면을 디자인해줍니다.
이미지를 선택하기 전에 기본 이미지 아이콘을 만들어줍니다.
import 'package:flutter/material.dart';
class Example1Page extends StatefulWidget {
const Example1Page({Key? key}) : super(key: key);
@override
State<Example1Page> createState() => _Example1PageState();
}
class _Example1PageState extends State<Example1Page> {
@override
Widget build(BuildContext context) {
final imageSize = MediaQuery.of(context).size.width / 4;
return Scaffold(
appBar: AppBar(title: const Text('Example1'),),
body: Column(
children: [
Container(
constraints: BoxConstraints(
minHeight: MediaQuery.of(context).size.width,
minWidth: MediaQuery.of(context).size.width,
),
child: Center(
child: Icon(
Icons.account_circle,
size: imageSize,
),
),
),
],
),
);
}
}
사진 아이콘을 누를경우 카메라와, 사진 라이브러리에 접근할수 있도록 bottomModalSheet 불러오는 이벤트를 만들어주고 bottomModalSheet에 버튼을 만들어줍니다.
import 'package:flutter/material.dart';
class Example1Page extends StatefulWidget {
const Example1Page({Key? key}) : super(key: key);
@override
State<Example1Page> createState() => _Example1PageState();
}
class _Example1PageState extends State<Example1Page> {
@override
Widget build(BuildContext context) {
final _imageSize = MediaQuery.of(context).size.width / 4;
return SafeArea(
child: Scaffold(
appBar: AppBar(
title: const Text('Example1'),
),
body: Column(
children: [
Container(
constraints: BoxConstraints(
minHeight: _imageSize,
minWidth: _imageSize,
),
child: GestureDetector(
onTap: () {
_showBottomSheet();
},
child: Center(
child: Icon(
Icons.account_circle,
size: imageSize,
),
),
),
),
],
),
),
);
}
_showBottomSheet() {
return showModalBottomSheet(
context: context,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
top: Radius.circular(25),
),
),
builder: (context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
const SizedBox(
height: 20,
),
ElevatedButton(
onPressed: () {},
child: const Text('사진찍기'),
),
const SizedBox(
height: 10,
),
const Divider(
thickness: 3,
),
const SizedBox(
height: 10,
),
ElevatedButton(
onPressed: () {},
child: const Text('라이브러리에서 불러오기'),
),
const SizedBox(
height: 20,
),
],
);
},
);
}
}
반응형
기본적인 UI작업은 끝이 났다 이제 카메라나 라이브러리 이미지를 불러와서 사용할 부분을 구현해보자.
먼저 파일을 받을 변수를 하나 선언해주자
XFile? _pickedFile;
해당 변수가 null인경우 이전에 만들어논 아이콘 이미지를 보여주고 해당 변수에 값이 들어오면 해당하는 이미지를 보여주는 부분을 구현해보자.
body: Column(
children: [
if (_pickedFile == null)
Container(
constraints: BoxConstraints(
minHeight: _imageSize,
minWidth: _imageSize ,
),
child: GestureDetector(
onTap: () {
_showBottomSheet();
},
child: Center(
child: Icon(
Icons.account_circle,
size: imageSize,
),
),
),
)
else
Container(
width: _imageSize,
height: _imageSize,
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
width: 2, color: Theme.of(context).colorScheme.primary),
image: DecorationImage(
image: FileImage(File(_pickedFile!.path)),
fit: BoxFit.cover),
),
),
],
),
이제 카메라를 불러오는 부분을 구현해보자 iOS는 에뮬레이터에서 카메라가 작동안하기 때문에 안드로이드로 테스트를 하였다.
카메라 연동하기를 구현한다.
_getCameraImage() async {
final pickedFile = await ImagePicker().pickImage(source: ImageSource.camera);
if (pickedFile != null) {
setState(() {
_pickedFile = pickedFile;
});
} else {
if (kDebugMode) {
print('이미지 선택안함');
}
}
}
갤러리 불러오기를 구현한다.
_getPhotoLibraryImage() async {
final pickedFile =
await ImagePicker().pickImage(source: ImageSource.gallery);
if (pickedFile != null) {
setState(() {
_pickedFile = _pickedFile;
});
} else {
if (kDebugMode) {
print('이미지 선택안함');
}
}
}
해당 함수를 버튼과 연결해준다.
_showBottomSheet() {
return showModalBottomSheet(
context: context,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
top: Radius.circular(25),
),
),
builder: (context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
const SizedBox(
height: 20,
),
ElevatedButton(
onPressed: () => _getCameraImage(),
child: const Text('사진찍기'),
),
const SizedBox(
height: 10,
),
const Divider(
thickness: 3,
),
const SizedBox(
height: 10,
),
ElevatedButton(
onPressed: () => _getPhotoLibraryImage(),
child: const Text('라이브러리에서 불러오기'),
),
const SizedBox(
height: 20,
),
],
);
},
);
}
최종 소스 코드
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
class Example1Page extends StatefulWidget {
const Example1Page({Key? key}) : super(key: key);
@override
State<Example1Page> createState() => _Example1PageState();
}
class _Example1PageState extends State<Example1Page> {
XFile? _pickedFile;
@override
Widget build(BuildContext context) {
final _imageSize = MediaQuery.of(context).size.width / 4;
return SafeArea(
child: Scaffold(
appBar: AppBar(
title: const Text('Example1'),
),
body: Column(
children: [
const SizedBox(height: 20,),
if (_pickedFile == null)
Container(
constraints: BoxConstraints(
minHeight: _imageSize,
minWidth: _imageSize,
),
child: GestureDetector(
onTap: () {
_showBottomSheet();
},
child: Center(
child: Icon(
Icons.account_circle,
size: _imageSize,
),
),
),
)
else
Center(
child: Container(
width: _imageSize,
height: _imageSize,
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
width: 2, color: Theme.of(context).colorScheme.primary),
image: DecorationImage(
image: FileImage(File(_pickedFile!.path)),
fit: BoxFit.cover),
),
),
),
],
),
),
);
}
_showBottomSheet() {
return showModalBottomSheet(
context: context,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
top: Radius.circular(25),
),
),
builder: (context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
const SizedBox(
height: 20,
),
ElevatedButton(
onPressed: () => _getCameraImage(),
child: const Text('사진찍기'),
),
const SizedBox(
height: 10,
),
const Divider(
thickness: 3,
),
const SizedBox(
height: 10,
),
ElevatedButton(
onPressed: () => _getPhotoLibraryImage(),
child: const Text('라이브러리에서 불러오기'),
),
const SizedBox(
height: 20,
),
],
);
},
);
}
_getCameraImage() async {
final pickedFile =
await ImagePicker().pickImage(source: ImageSource.camera);
if (pickedFile != null) {
setState(() {
_pickedFile = pickedFile;
});
} else {
if (kDebugMode) {
print('이미지 선택안함');
}
}
}
_getPhotoLibraryImage() async {
final pickedFile =
await ImagePicker().pickImage(source: ImageSource.gallery);
if (pickedFile != null) {
setState(() {
_pickedFile = _pickedFile;
});
} else {
if (kDebugMode) {
print('이미지 선택안함');
}
}
}
해당 소스는 깃허브에서 확인해 볼수 있다.
반응형
'DEV > FLUTTER' 카테고리의 다른 글
Admob 광고 안나오는 문제 수정 (0) | 2022.07.06 |
---|---|
파이어베이스 에뮬레이터 (firebase emulator) 실행 문제 (0) | 2022.07.04 |
[FLUTTER] IOS 구글 로그인 (google sign in) 취소시 앱 크래쉬 (0) | 2022.06.24 |
[FLUTTER] 프로필 화면 만들기 #2 ( Image Crop) (0) | 2022.06.05 |