dependencies:
image_picker: ^0.8.4+4
<key>NSPhotoLibraryUsageDescription</key>
<string>사진첩좀 써도 됩니까</string>
<key>NSCameraUsageDescription</key>
<string>카메라좀 써도 됩니까</string>
<key>NSMicrophoneUsageDescription</key>
<string>마이크 권한좀 제발</string>
import 'package:image_picker/image_picker.dart';
import 'dart:io';
onPressed: () async {
var picker = ImagePicker();
var image = await picker.pickImage(source: ImageSource.gallery);
}
⇒ 이미지 선택 화면 뜨는 코드
→ 고른 이미지 사이즈, 화질 조정도 가능
→ photofilters 패키지 설치하면 이미지에 필터 씌울 수 있음
onPressed: () async {
var picker = ImagePicker();
var image = await picker.pickImage(source: ImageSource.gallery);
if (image != null) { // 선택 안하면 null이므로 체크
setState((){
userImage = File(image.path);
});
}
}
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:flutter/rendering.dart';
import 'package:image_picker/image_picker.dart';
import 'dart:io';
void main() {
runApp(
MaterialApp(
theme: style.theme,
home: MyApp()
));
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
var tab = 0; // 1. 현재 상태 저장
var list = [1, 2, 3];
var map = {'name':'john', 'age':20};
var data = [];
var userImage;
addData(a) {
setState(() {
data.add(a);
});
}
getData() async {
var result = await http.get(Uri.parse('https://codingapple1.github.io/app/data.json'));
var result2 = jsonDecode(result.body);
setState(() {
data = result2;
});
}
void initState() {
super.initState();
getData();
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Instagram'),
actions: [
IconButton(
icon: Icon(Icons.add_box_outlined),
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) )
);
},
iconSize: 30,
)
]),
body: [Home(data : data, addData : addData), Text('샵페이지')][tab], // 2. state에 따라 tab 보이는 상태 변경
bottomNavigationBar: BottomNavigationBar(
showSelectedLabels: false,
showUnselectedLabels: false,
onTap: (i){
setState(() {
tab = i;
});
},
items: [
BottomNavigationBarItem(icon: Icon(Icons.home_outlined), label: '홈'),
BottomNavigationBarItem(icon: Icon(Icons.shopping_bag_outlined), label: '샵')
],
),
);
}
}
class Home extends StatefulWidget {
const Home({Key? key, this.data, this.addData}) : super(key: key);
final data, addData;
State<Home> createState() => _HomeState();
}
class _HomeState extends State<Home> {
var scroll = ScrollController();
getMore() async {
var result = await http.get(Uri.parse('https://codingapple1.github.io/app/more1.json'));
var result2 = jsonDecode(result.body);
widget.addData(result2);
}
void initState() {
super.initState();
scroll.addListener(() { // 스크롤바 높이 측정 코드
if(scroll.position.pixels == scroll.position.maxScrollExtent) {
getMore();
}
});
}
Widget build(BuildContext context) {
if (widget.data.isNotEmpty) {
return ListView.builder(
itemCount: widget.data.length,
controller: scroll,
itemBuilder: (c, i) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.network(widget.data[i]['image']),
Container(
constraints: BoxConstraints(maxWidth: 600),
padding: EdgeInsets.all(20),
width: double.infinity,
child: Column(
children: [
Text('좋아요 ${widget.data[i]['likes'].toString()}'),
Text(widget.data[i]['date']),
Text(widget.data[i]['content'])
],
),
)
],
);
}
);
} else {
return Text('로딩중임');
}
}
}
class Upload extends StatelessWidget {
const Upload({Key? key, this.userImage}) : super(key: key);
final userImage;
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.file(userImage),
Text('이미지업로드화면'),
TextField(),
IconButton(
onPressed: (){
Navigator.pop(context);
},
icon: Icon(Icons.close)
),
],
)
);
}
}
→ 발행 버튼 누르면 유저가 입력한 글과 사진 게시물로 보여주기
우선 발행 버튼 하나 만들고
Scaffold(
resizeToAvoidBottomInset: false,
appBar: AppBar( actions: [
IconButton(onPressed: (){}, icon: Icon(Icons.send))
]),
(생략)
유저가 입력한 글과 사진을 MyApp 안에 state에 저장해둠
class _MyAppState extends State<MyApp> {
var tab = 0;
var data = [];
var userImage;
var userContent;
setUserContent(a){
setState(() {
userContent = a;
});
}
(생략)
(Upload페이지)
TextField(onChanged: (text){ setUserContent(text); })발행 버튼 누르면 var data = [] 에 게시물 데이터 하나 추가
data.insert(0, 자료) 사용class _MyAppState extends State<MyApp> {
var tab = 0;
var data = [];
var userImage;
var userContent;
addMyData(){
var myData = {
'id': data.length,
'image': userImage,
'likes': 5,
'date': 'July 25',
'content': userContent,
'liked': false,
'user': 'John Kim'
};
setState(() {
data.insert(0, myData);
});
}
(생략)
Scaffold(
resizeToAvoidBottomInset: false,
appBar: AppBar( actions: [
IconButton(onPressed: (){ addMyData(); }, icon: Icon(Icons.send))
]),
(생략)이상한 건 if문으로 예외 처리
- 3번까지 하고 돌리면 콘솔창에 에러남
- type '_File' is not a subtype of type 'String’
- 이미지 보여줄 때 Image.network() 여기에 ‘https://어쩌구’ 이런 거 넣어서 보여주고 있는데 사용자가 선택한 건 File 타입이기 때문에 타입 에러 발생
- 그래서 삼중 연산자를 통해 이미지 경로가 문자이면 무엇을, 그에 아니라면 이것을 보여달라고 코드 구현
Image.network(widget.data[i]['image'])
// -> 이렇게 변경
widget.data[i]['image'].runtimeType == String
? Image.network(widget.data[i]['image'])
: Image.file(widget.data[i]['image']),