1. add_place 화면에 맵 스크린 화면을 사용해보자.
- location_input.dart
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:location/location.dart';
import 'package:http/http.dart' as http;
import 'package:favorite_places/screens/map.dart';
import 'package:favorite_places/models/place.dart';
class LocationInput extends StatefulWidget {
const LocationInput({super.key, required this.onSelectLocation});
final void Function(PlaceLocation location) onSelectLocation;
@override
State<LocationInput> createState() {
return _LocationInputState();
}
}
class _LocationInputState extends State<LocationInput> {
PlaceLocation? _pickedLocation;
var _isGettingLocation = false;
String get locationImage {
if (_pickedLocation == null) {
return '';
}
final lat = _pickedLocation!.latitude;
final lng = _pickedLocation!.longitude;
return 'https://maps.googleapis.com/maps/api/staticmap?center=$lat,$lng=&zoom=16&size=600x300&maptype=roadmap&markers=color:red%7Clabel:A%7C$lat,$lng&key=AIzaSyDLcwxUggpPZo8lcbH0TB4Crq5SJjtj4ag';
}
Future<void> _savePlace(double latitude, double longitude) async {
final url = Uri.parse(
'https://maps.googleapis.com/maps/api/geocode/json?latlng=$latitude,$longitude&key=AIzaSyDLcwxUggpPZo8lcbH0TB4Crq5SJjtj4ag');
final response = await http.get(url);
final resData = json.decode(response.body);
final address = resData['results'][0]['formatted_address'];
setState(() {
_pickedLocation = PlaceLocation(
latitude: latitude,
longitude: longitude,
address: address,
);
_isGettingLocation = false;
});
widget.onSelectLocation(_pickedLocation!);
}
void _getCurrentLocation() async {
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;
}
}
setState(() {
_isGettingLocation = true;
});
locationData = await location.getLocation();
final lat = locationData.latitude;
final lng = locationData.longitude;
if (lat == null || lng == null) {
return;
}
_savePlace(lat, lng);
}
void _selectOnMap() async {
final pickedLocation = await Navigator.of(context).push<LatLng>(
MaterialPageRoute(
builder: (ctx) => const MapScreen(),
),
);
if (pickedLocation == null) {
return;
}
_savePlace(pickedLocation.latitude, pickedLocation.longitude);
}
@override
Widget build(BuildContext context) {
Widget previewContent = Text(
'No location chosen',
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.bodyLarge!.copyWith(
color: Theme.of(context).colorScheme.onBackground,
),
);
if (_pickedLocation != null) {
previewContent = Image.network(
locationImage,
fit: BoxFit.cover,
width: double.infinity,
height: double.infinity,
);
}
if (_isGettingLocation) {
previewContent = const CircularProgressIndicator();
}
return Column(
children: [
Container(
height: 170,
width: double.infinity,
alignment: Alignment.center,
decoration: BoxDecoration(
border: Border.all(
width: 1,
color: Theme.of(context).colorScheme.primary.withOpacity(0.2),
),
),
child: previewContent,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
TextButton.icon(
icon: const Icon(Icons.location_on),
label: const Text('Get Current Location'),
onPressed: _getCurrentLocation,
),
TextButton.icon(
icon: const Icon(Icons.map),
label: const Text('Select on Map'),
onPressed: _selectOnMap,
),
],
),
],
);
}
}
1) 현재 위치를 받든, 맵에서 새로운 위치를 얻어오든 _savePlace 함수를 통해, 상위 위젯인 add_place로 그 값이 전달된다.
- map.dart
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:favorite_places/models/place.dart';
class MapScreen extends StatefulWidget {
const MapScreen({
super.key,
this.location = const PlaceLocation(
latitude: 37.422,
longitude: -122.084,
address: '',
),
this.isSelecting = true,
});
final PlaceLocation location;
final bool isSelecting;
@override
State<MapScreen> createState() {
return _MapScreenState();
}
}
class _MapScreenState extends State<MapScreen> {
LatLng? _pickedLocation;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title:
Text(widget.isSelecting ? 'Pick your Location' : 'Your Location'),
actions: [
if (widget.isSelecting)
IconButton(
icon: const Icon(Icons.save),
onPressed: () {
Navigator.of(context).pop(_pickedLocation);
},
),
]),
body: GoogleMap(
onTap: !widget.isSelecting
? null
: (position) {
setState(() {
_pickedLocation = position;
});
},
initialCameraPosition: CameraPosition(
target: LatLng(
widget.location.latitude,
widget.location.longitude,
),
zoom: 16,
),
markers: (_pickedLocation == null && widget.isSelecting)
? {}
: {
Marker(
markerId: const MarkerId('m1'),
position: _pickedLocation ??
LatLng(
widget.location.latitude,
widget.location.longitude,
),
),
},
),
);
}
}
1) pop을 할 때, _pickedLocation을 상위 위젯인 location_input에 전달해준다.
2) place_detail 화면에서 써클 아바타를 눌렀을 시(isSelecting == false), 다시 지도 선택을 할 수 없도록 아래와 같이 isSelecting 조건부를 건다.
onTap: !widget.isSelecting
? null
: (position) {
setState(() {
_pickedLocation = position;
});
},
3) 마커 부분 아래 내용은, 3가지 경우의 수를 다룬다.
1. location input 화면에서 터치하고 들어 왔을 때 최초 화면은 마커가 없다. (_pickedLocation == null 이고, isSelecting은 true이기 때문에 조건 부합)
2. location input 화면에서 터치하고 들어 온 후, _pickedLocation 값이 생기면(화면 터치 후) 마커가 생긴다.
3. place_detail 화면에서 들어 오면, 마커가 보인다. (하지만 위 onTap로직에 의해 터치를 통한 새로운 마커는 불가)
markers: (_pickedLocation == null && widget.isSelecting)
? {}
: {
Marker(
markerId: const MarkerId('m1'),
position: _pickedLocation ??
LatLng(
widget.location.latitude,
widget.location.longitude,
),
),
'코딩강의 > favorite_places(플러터-유데미)' 카테고리의 다른 글
~262. Using a FutureBuilder for Loading Data (1) | 2023.11.22 |
---|---|
~259. Storing the Picked Image Locally (1) | 2023.11.21 |
~255. Displaying the Picked Place on a Dynamic Map (0) | 2023.11.21 |
~252. Outputting the Location Data (1) | 2023.11.21 |
~250. Displaying a Location Preview Map Snapshot via Google (0) | 2023.11.20 |