폰에 저장된 이미지 가져오기 (Image Picker)
- 우선 플러그인을 하나 설치해야 하기에 pubspec.yaml에서 코드 기입
- 이후 전구를 클릭 해서 Pub get 해주기
dependencies:
flutter:
sdk: flutter
http: ^0.13.4
image_picker: ^0.8.4+4
- 이후 ios/Runner/Info.plist 에서 아래의 코드를 기입 해주기
- 해당 코드는 허락 받는 코드가 되고
- 안드로이드는 필요 없는데
- IOS에서는 필요해서 작성해줘야 함.
<dict> <key>NSPhotoLibraryUsageDescription</key> <string>사진첩좀 써도 됩니까</string> <key>NSCameraUsageDescription</key> <string>카메라좀 써도 됩니까</string> <key>NSMicrophoneUsageDescription</key> <string>마이크 권한좀 제발</string>
- 해당 코드는 허락 받는 코드가 되고
- 이제 main.dart 파일로 돌아가서 아래의 코드를 기입해 사용하기
- import 'package:image_picker/image_picker.dart'; import 'dart:io';
- 가져오는 코드 작성하기
- picker 변수에 ImagePicker() 위젯을 담아주기
- 이후 image 변수에 picker.pickImage() 위젯으로 source: ImageSource.gallery 를 작성
- 여기서 처리하는 시간이 길기에 async, await을 사용해주기
IconButton( onPressed: () async{ var picker = ImagePicker(); var image = await picker.pickImage(source: ImageSource.gallery); Navigator.push(context, MaterialPageRoute(builder: (c) => Upload() ) ); }, icon: Icon(Icons.add_box_outlined) )
- 이때 사진첩이 아닌 카메라를 켜고 싶다면 ImageSource.camera 를 작성하면 된다.
- 비디오를 선택하고 싶다면
- var image = await picker.pickVideo();
- 한 장이 아닌 여러 사진을 가져오고 싶다면
- pickMultiImage() 를 사용하기
- 이제 선택한 사진을 보여주기
- 상단에 변수를 만든 후 onPressed(){} 안에 담아주기
- userImage = File(image.path);
- 그런데 이렇게만 하면 에러가 발생할 수 있다.
- 이유는 선택하지 않았을 경우 Null 이기에 걱정을 하는 것인데
- 이럴 땐 조건문을 사용해주면 된다.
IconButton( onPressed: () async{ var picker = ImagePicker(); var image = await picker.pickImage(source: ImageSource.gallery); if (image != null) { userImage = File(image.path); } Navigator.push(context, MaterialPageRoute(builder: (c) => Upload() ) ); }, icon: Icon(Icons.add_box_outlined) )
- 다만 userImage 또한 State이기에 setState를 통해 변경해야 반영될 수 있다.
- 상단에 변수를 만든 후 onPressed(){} 안에 담아주기
conButton(
onPressed: () async{
var picker = ImagePicker();
var image = await picker.pickImage(source: ImageSource.gallery);
if (image != null) {
setState(() {
userImage = File(image.path);
});
}
Navigator.push(context,
MaterialPageRoute(builder: (c) => Upload()
)
);
},
icon: Icon(Icons.add_box_outlined)
)
- 이후 파일 경로로 이미지를 띄우는 방법은
- Image.file(userImage); 로 작성하면 된다.
import 'package:flutter/material.dart'; import './style.dart' as style; import 'package:http/http.dart' as http; import 'dart:convert'; // 이미지 볼러오기 import 'package:image_picker/image_picker.dart'; import 'dart:io'; void main() { runApp( MaterialApp( theme: style.theme, initialRoute: '/', routes: { '/': (c) => MyApp(), '/mypage': (c) => Text('마이 페이지') }, // home: MyApp() ) ); } class MyApp extends StatefulWidget { MyApp({super.key}); @override State<MyApp> createState() => _MyAppState(); } class _MyAppState extends State<MyApp> { var homeData = []; appendData(value){ setState(() { homeData.add(value); }); } getData() async{ var result = await http.get(Uri.parse('경로')); if (result.statusCode == 200) { setState(() { homeData = jsonDecode(result.body); }); } else { print('실패'); } } @override void initState() { super.initState(); getData(); } // 0: home, 1: shop var tab = 0; var userImage; changeTab(tabNumber){ setState(() { tab = tabNumber; }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Instagram'), actions: [ IconButton( onPressed: () async{ var picker = ImagePicker(); var image = await picker.pickImage(source: ImageSource.gallery); if (image != null) { setState(() { userImage = File(image.path); }); } Navigator.push(context, MaterialPageRoute(builder: (c) => Upload(userImage:userImage) ) ); }, icon: Icon(Icons.add_box_outlined) ) ], ), body: [Home(homeData:homeData, appendData:appendData),Text('shop')][tab], bottomNavigationBar: BottomNavigationBar( onTap: (i){ changeTab(i); }, items: [ BottomNavigationBarItem( icon: Icon(Icons.home_outlined), label: 'Home', ), BottomNavigationBarItem( icon: Icon(Icons.shopping_bag_outlined), label: 'Shopping', ), ], showSelectedLabels: false, // 선택된 아이템의 레이블 숨김 showUnselectedLabels: false, // 선택되지 않은 아이템의 레이블 숨김 ), ); } } // Home class Home extends StatefulWidget { Home({super.key, this.homeData, this.appendData}); final homeData; final appendData; @override State<Home> createState() => _HomeState(); } class _HomeState extends State<Home> { // ScrollController() 는 자료를 저장해주는 것으로, 클래스가 된다. 그래서 스크롤 정보를 저장해주는 것을 하는데 도움을 준다 var scroll = ScrollController(); var cnt = 0; getAddData() async{ cnt ++; print(cnt); var data = await http.get(Uri.parse('경로')); if (data.statusCode == 200){ widget.appendData(jsonDecode(data.body)); } else { print('더 이상 없어'); } } @override void initState() { super.initState(); scroll.addListener(() { if (scroll.position.pixels == scroll.position.maxScrollExtent) { getAddData(); } }); } @override Widget build(BuildContext context) { if (widget.homeData.isNotEmpty){ return ListView.builder( controller: scroll, itemCount: widget.homeData.length, itemBuilder: (context, idx){ return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Image.network(widget.homeData[idx]['image']), Container( margin: EdgeInsets.fromLTRB(10, 20, 10, 20), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Text('좋아요 ${widget.homeData[idx]['likes'].toString()}', style: TextStyle(fontSize: 15, fontWeight: FontWeight.w700),), ], ), Text(widget.homeData[idx]['date'].toString()), Text(widget.homeData[idx]['content'].toString()), ], ), ) ], ); }, ); } else { return Text('빈'); } } } // Upload class Upload extends StatelessWidget { Upload({Key? key, this.userImage}) : super(key: key); @override final userImage; Widget build(BuildContext context) { return Scaffold( appBar: AppBar(), body: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('선택한 이미지'), Image.file(userImage), IconButton( onPressed: (){ Navigator.pop(context); }, icon: Icon(Icons.close) ), ], ) ); } }
- 다만 Don't use 'BuildContext's across async gaps. 이런 경고가 발생하는데
- 이유는 위젯이 마운트되지 않으면 async뒤에 context를 썻을 때 그 안에 아무런 값도 들어있지 않을 수 있어서라고 한다.
- 즉 IconButton에서 await 코드를 아래로 빼니까 경고가 사라졌다.
conButton(
onPressed: () async{
var picker = ImagePicker();
var image = await picker.pickImage(source: ImageSource.gallery);
if (image != null) {
setState(() {
userImage = File(image.path);
});
}
Navigator.push(context,
MaterialPageRoute(builder: (c) => Upload()
)
);
},
icon: Icon(Icons.add_box_outlined)
)
- 그리고 다른 사진 어플에 있는 것처럼 필터나 사진 크기 등을 변경하고자 한다면 아래의 경로에 있는 패키지를 설치해서 사용하면 된다.
숙제
발행 버튼 누르면 글 발행하기 흠 우선 휴대폰에서 선택한 사진은
Image.network가 아닌 Image.file로 해줘야 하기에
우선 에러 문구를 보면 String 타입의 경우엔 Image.network() 를 사용하라고 하니까
해당 데이터의 타입을 확인해보고 조건 분기 처리를 하면 될 듯하다.
해당 데이터의 타입을 확인해보고 싶다면 .runtimeType을 붙여주면 된다.
// Home
class Home extends StatefulWidget {
Home({super.key, this.homeData, this.appendData});
final homeData;
final appendData;
@override
State<Home> createState() => _HomeState();
}
class _HomeState extends State<Home> {
// ScrollController() 는 자료를 저장해주는 것으로, 클래스가 된다. 그래서 스크롤 정보를 저장해주는 것을 하는데 도움을 준다
var scroll = ScrollController();
var cnt = 0;
getAddData() async{
cnt ++;
print(cnt);
var data = await http.get(Uri.parse('주소'));
if (data.statusCode == 200){
widget.appendData(jsonDecode(data.body));
} else {
print('더 이상 없어');
}
}
@override
void initState() {
super.initState();
scroll.addListener(() {
if (scroll.position.pixels == scroll.position.maxScrollExtent) {
getAddData();
}
});
}
@override
Widget build(BuildContext context) {
if (widget.homeData.isNotEmpty){
return ListView.builder(
controller: scroll,
itemCount: widget.homeData.length,
itemBuilder: (context, idx){
print(idx);
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
widget.homeData[idx]['image'].runtimeType == String?Image.network(widget.homeData[idx]['image']):Image.file(widget.homeData[idx]['image']),
Container(
margin: EdgeInsets.fromLTRB(10, 20, 10, 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Text('좋아요 ${widget.homeData[idx]['likes'].toString()}', style: TextStyle(fontSize: 15, fontWeight: FontWeight.w700),),
],
),
Text(widget.homeData[idx]['date'].toString()),
Text(widget.homeData[idx]['content'].toString()),
],
),
)
],
);
},
);
} else {
return Text('빈');
}
}
}
// Upload
class Upload extends StatefulWidget {
Upload({Key? key, this.userImage, this.appendData, this.homeData}) : super(key: key);
@override
final userImage;
final appendData;
final homeData;
@override
State<Upload> createState() => _UploadState();
}
class _UploadState extends State<Upload> {
var inputValue = '';
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('선택한 이미지'),
Image.file(widget.userImage),
TextField(onChanged: (val){setState(() {
inputValue = val;
});}),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
IconButton(
onPressed: (){
Navigator.pop(context);
},
icon: Icon(Icons.close)
),
IconButton(
onPressed: (){
// print(widget.userImage);
var val = {'id': 3, 'image': widget.userImage, 'likes': 0, 'date': 'Aug 11', 'content': inputValue, 'liked': false, 'user': 'Hminor'};
widget.appendData(val);
Navigator.pop(context);
},
icon: Icon(Icons.add)
),
],
)
],
)
);
}
}
그리고 추가한 게시글이 가장 앞에 위치하고자 한다면 add가 아닌
insert(idx, value) 로 추가해주면 idx 번째에 추가해주는 것을 의미한다.
'Flutter' 카테고리의 다른 글
[Flutter] GestureDetector & 페이지 전환 애니메이션 (CupertinoPageRoute,PageRouteBuilder) (0) | 2023.08.12 |
---|---|
[Flutter] DB 없이 데이터 저장하는 방법 (Shared Preferences) (0) | 2023.08.11 |
[Flutter] 상세페이지 만들기 (Navigator, Routes) (0) | 2023.08.10 |
[Flutter] 스크롤 위치 파악 & 무한 스크롤 (0) | 2023.08.10 |
[Flutter] Future 다루기 & FutureBuilder (0) | 2023.08.09 |