https://pub.dev/packages/image_picker
Flutter 에서 카메라로 촬영한 사진 혹은 갤러리의 이미지를 가져올때 Image_picker 패키지로 구현이 가능하다
File? _selectedImage;
void _takePicture() async {
final imagePicker = ImagePicker();
final pickedImage =
await imagePicker.pickImage(source: ImageSource.camera, maxWidth: 600);
if (pickedImage == null) {
return;
}
setState(() {
_selectedImage = File(pickedImage.path);
});
widget.onPickImage(_selectedImage!);
}
TakePicture 함수는
패키지를 활용하여, ImageSource.camera로 카메라로 찍은 사진을 바로 업로드 하여 PickedImage 변수에 저장,
(ImageSource.gallery로 갤러리에서 찍었던 사진을 가져올 수도 있다.)
이 함수를 버튼의 OnTap 에 달아서 사용자가 버튼을 누르면, 사진을 찍고 이를 업로드 할 수 있도록 하였다.
https://pub.dev/packages/location
사용자의 핸드폰 위치정보를 가져올 수 있는 패키지 이다.
적용시 버전 오류가 많이 나는 것 같다.(나를 포함하여...)
Error
코틀린 버전이 너무 오래되어 location 패키지와 호환이 불가능
-> 그 밑에 바로 해결법이 나온다
Solved
해당 path 로 들어가 buildscript의 코틀린 버전을 최신버전으로 업그레이드 시켜주면 된다.


일단 위치 라이브러리를 활용하는 UI는 다음과 같다,
Scaffold -> Appbar -> SingleChildScrollView -> Column -> Textfield/ImageInput/LocationInput/ElevatedButton
의 구조로 되어있다.
LocationInput에 지도 출력관련에서 API 링크가 잘못된건지 위치 정보 로드는 잘 되는데 지도 화면이 나타나지를 않는다
void _getCurrentLocation() async {
setState(() {
_isGettingLocation = true;
});
Location location = Location();
bool serviceEnabled;
PermissionStatus permissionGranted;
LocationData locationData;
// 서비스 가능여부 확인 코드
serviceEnabled = await location.serviceEnabled();
if (!serviceEnabled) {
serviceEnabled = await location.requestService();
if (!serviceEnabled) {
return;
}
}
// 사용자 허가 확인 여부 체크
permissionGranted = await location.hasPermission();
if (permissionGranted == PermissionStatus.denied) {
permissionGranted = await location.requestPermission();
if (permissionGranted != PermissionStatus.granted) {
return;
}
}
locationData = await location.getLocation();
final lat = locationData.latitude;
final lng = locationData.longitude;
if (lat == null || lng == null) {
return;
}
_savePlace(lat, lng);
}
Location 타입의 위치정보를 locationData로 가져와서
우리 사람이 읽을 수 있는 주소인 위,경도(lat,lng)로 변환하여 저장하는 기능을 하는 함수이다.
값이 비었는지 유효성검사를 하고 저장한다.
https://codelabs.developers.google.com/codelabs/google-maps-in-flutter?hl=ko#2
아주 친절하게 단계별로 나와있어 잠시 빌려보도록 하자면
기본적인 flutter 구성이 완료 되었다면
https://pub.dev/packages/google_maps_flutter
위 패키지를 추가하고,
IOS/Android 별로 추가로 또 뭔갈 해야 사용이 가능하다.
IOS(PodFile) 같은경우 버전이 11.0 이상,
안드로이드(build.gradle)는 minSdkVersion을 20 으로 바꾸어 주어야 한다.
그리고 안드로이드에는 AndroidManifest.xml 파일에 자신의 APIKEY 를 담아서 메타 데이터를 추가 해주어야 한다.
GoogleMap(
onTap: !widget.isSelecting
? null
: (position) {
setState(() {
_pickedLoctiaon = position;
});
},
initialCameraPosition: CameraPosition(
target: LatLng(
widget.location.latitude,
widget.location.longitude,
),
zoom: 16,
),
markers: (_pickedLoctiaon == null && widget.isSelecting)
? {}
: {
Marker(
markerId: const MarkerId('m1'),
position: _pickedLoctiaon ??
LatLng(
widget.location.latitude,
widget.location.longitude,
),
),
},
),
);
Location 데이터를 Provider를 사용하여 한곳에서 관리하고 있음을 알린다.
class UserPlacesNotifier extends StateNotifier<List<Place>> {
// 초기 값 전달(빈 리스트)
UserPlacesNotifier() : super(const []);
Future<void> loadPlaces() async {
final db = await _getDatabase();
final data = await db.query('user_places');
final places = data
.map(
(row) => Place(
id: row['id'] as String,
title: row['title'] as String,
image: File(row['image'] as String),
location: PlaceLocation(
latitude: row['lat'] as double,
longitude: row['lng'] as double,
address: row['address'] as String),
),
)
.toList();
state = places;
}
우리에게 데이터베이스가 없다면, 폰을 껏다가 키면 그동안 저장했던 데이터가 사라진다.
https://pub.dev/packages/path_provider
=> 운영체제에 의해 데이터 삭제를 방지하는 패키지
https://pub.dev/packages/path/install
=> 경로를 간소화하는 패키지
https://pub.dev/packages/sqflite/install
=> SQL DB를 flutter code로 생성가능토록 만드는 이미지
import 'package:path_provider/path_provider.dart' as syspaths;
import 'package:path/path.dart' as path;
import 'package:sqflite/sqflite.dart' as sql;
import 'package:sqflite/sqlite_api.dart';
Future<Database> _getDatabase() async {
final dbPath = await sql.getDatabasesPath();
final db = await sql.openDatabase(
path.join(dbPath, 'places.db'),
onCreate: (db, version) {
return db.execute(
'CREATE TABLE user_places(id TEXT PRIMARY KEY, title TEXT, image TEXT, location TEXT, lat REAL, lon REAL, lng REAL, address TEXT)');
},
// 데이터 변경시마다 이 값이 1씩 올라간다
version: 1,
);
return db;
}
이렇게 SQL 문법을 활용하여 필요한 데이터베이스를 만들고 여기 데이터를 저장할 수 있다.
void addPlace(String title, File image, PlaceLocation location) async {
final appDir = await syspaths.getApplicationCacheDirectory();
final filename = path.basename(image.path);
final copiedImage = await image.copy('${appDir.path}/$filename');
final newPlace =
Place(title: title, image: copiedImage, location: location);
final db = await _getDatabase();
db.insert('user_places', {
'id': newPlace.id,
'title': newPlace.title,
'image': newPlace.image.path,
'lat': newPlace.location.latitude,
'lng': newPlace.location.longitude,
'address': newPlace.location.address
});
// spread operator 를 통해 state가 바뀌어도 기존 내용을 잃어버리지 않도록
state = [newPlace, ...state];
}
insert 키워드를 활용하여 Place 클래스로 들어오는 장소 제목과 이미지, 위치 정보를 db에 집어넣을 수 있다.
Future 타입의 데이터를 가져오기 때문에 async await을 활용하였다.