NaverMap 의존성 추가
dependencies:
flutter_naver_map: [최신버전]
https://pub.dev/packages/flutter_naver_map
naver map api 사용 설정
https://console.ncloud.com/naver-service/application
Flutter code
naver map 화면 추가
더보기
import 'dart:async';
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_naver_map/flutter_naver_map.dart';
class BaseMapPage extends StatefulWidget {
const BaseMapPage({Key? key}) : super(key: key);
@override
_BaseMapPageState createState() => _BaseMapPageState();
}
class _BaseMapPageState extends State<BaseMapPage> {
final scaffoldKey = GlobalKey<ScaffoldState>();
Completer<NaverMapController> _controller = Completer();
MapType _mapType = MapType.Basic;
final LocationTrackingMode _trackingMode = LocationTrackingMode.Follow;
@override
Widget build(BuildContext context) {
return Scaffold(
key: scaffoldKey,
appBar: AppBar(),
body: Stack(
children: <Widget>[
NaverMap(
initialCameraPosition: const CameraPosition(
target: LatLng(37.566570, 126.978442),
zoom: 17,
),
onMapCreated: onMapCreated,
mapType: _mapType,
initLocationTrackingMode: _trackingMode,
locationButtonEnable: true,
indoorEnable: true,
onCameraChange: _onCameraChange,
onCameraIdle: _onCameraIdle,
onMapTap: _onMapTap,
onMapLongTap: _onMapLongTap,
onMapDoubleTap: _onMapDoubleTap,
onMapTwoFingerTap: _onMapTwoFingerTap,
onSymbolTap: _onSymbolTap,
maxZoom: 17,
minZoom: 12,
useSurface: kReleaseMode,
logoClickEnabled: true,
),
Padding(
padding: EdgeInsets.all(16),
child: _mapTypeSelector(),
),
_trackingModeSelector(),
],
),
);
}
_onMapTap(LatLng position) async {
await (await _controller.future).moveCamera(
CameraUpdate.toCameraPosition(CameraPosition(target: position)),
animationDuration: 1500);
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content:
Text('[onTap] lat: ${position.latitude}, lon: ${position.longitude}'),
duration: const Duration(milliseconds: 500),
backgroundColor: Colors.black,
));
}
_onMapLongTap(LatLng position) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(
'[onLongTap] lat: ${position.latitude}, lon: ${position.longitude}'),
duration: const Duration(milliseconds: 500),
backgroundColor: Colors.black,
));
}
_onMapDoubleTap(LatLng position) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(
'[onDoubleTap] lat: ${position.latitude}, lon: ${position.longitude}'),
duration: const Duration(milliseconds: 500),
backgroundColor: Colors.black,
));
}
_onMapTwoFingerTap(LatLng position) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(
'[onTwoFingerTap] lat: ${position.latitude}, lon: ${position.longitude}'),
duration: const Duration(milliseconds: 500),
backgroundColor: Colors.black,
));
}
_onSymbolTap(LatLng? position, String? caption) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(
'[onSymbolTap] caption: $caption, lat: ${position?.latitude ?? '-'}, lon: ${position?.longitude ?? '-'}'),
duration: const Duration(milliseconds: 500),
backgroundColor: Colors.black,
));
}
_mapTypeSelector() {
return SizedBox(
height: kToolbarHeight,
child: ListView.separated(
itemCount: MapType.values.length,
scrollDirection: Axis.horizontal,
separatorBuilder: (_, __) => const SizedBox(width: 16),
itemBuilder: (_, index) {
final type = MapType.values[index];
String title;
switch (type) {
case MapType.Basic:
title = '기본';
break;
case MapType.Navi:
title = '내비';
break;
case MapType.Satellite:
title = '위성';
break;
case MapType.Hybrid:
title = '위성혼합';
break;
case MapType.Terrain:
title = '지형도';
break;
}
return GestureDetector(
onTap: () => _onTapTypeSelector(type),
child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(6),
boxShadow: const [BoxShadow(color: Colors.black26, blurRadius: 3)]),
margin: const EdgeInsets.only(bottom: 16),
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 12),
child: Text(
title,
style: const TextStyle(
color: Colors.black87,
fontWeight: FontWeight.w600,
fontSize: 13),
),
),
);
},
),
);
}
_trackingModeSelector() {
return Align(
alignment: Alignment.bottomRight,
child: GestureDetector(
onTap: _onTapTakeSnapShot,
child: Container(
margin: const EdgeInsets.only(right: 16, bottom: 48),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(6),
color: Colors.white,
boxShadow: const [
BoxShadow(
color: Colors.black12,
blurRadius: 2,
)
]),
padding: const EdgeInsets.all(12),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: const <Widget>[
Icon(
Icons.photo_camera,
color: Colors.black54,
),
],
),
),
),
);
}
/// 지도 생성 완료시
void onMapCreated(NaverMapController controller) {
if (_controller.isCompleted) _controller = Completer();
_controller.complete(controller);
}
/// 지도 유형 선택시
void _onTapTypeSelector(MapType type) async {
if (_mapType != type) {
setState(() {
_mapType = type;
});
}
}
/// my location button
// void _onTapLocation() async {
// final controller = await _controller.future;
// controller.setLocationTrackingMode(LocationTrackingMode.Follow);
// }
void _onCameraChange(
LatLng? latLng, CameraChangeReason? reason, bool? isAnimated) {
print(
'카메라 움직임 >>> 위치 : ${latLng?.latitude ?? '-'}, ${latLng?.longitude ?? '-'}'
'\n원인: $reason'
'\n에니메이션 여부: $isAnimated');
}
void _onCameraIdle() {
print('카메라 움직임 멈춤');
}
/// 지도 스냅샷
void _onTapTakeSnapShot() async {
final controller = await _controller.future;
controller.takeSnapshot((path) {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
contentPadding: EdgeInsets.zero,
content: path != null
? Image.file(
File(path),
)
: const Text("path is null!"),
titlePadding: EdgeInsets.zero,
);
});
});
}
}
해당 코드는 pub dev의 naver map 예제 코드이므로 사용할 기능만 남겨놓고 수정하면 된다.
Android code 작성
android/app/src/main/AndroidManifest.xml 파일에 다음 코드 작성
<manifest
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<application
...
<meta-data
android:name="flutterEmbedding"
android:value="2" />
<meta-data
android:name="com.naver.maps.map.CLIENT_ID"
android:value="Naver Client ID 입력" />
</application>
</manifest>
IOS code 작성
ios/Runner/Info.plist
<dict>
...
<!-- naver map -->
<key>NMFClientId</key>
<string>Naver Client ID 입력</string>
</dict>
그 외 Android 및 IOS 권한관련 코드 작성
https://kanoos-stu.tistory.com/64
'Flutter' 카테고리의 다른 글
[Flutter] Dart에서 const와 final의 차이점 (0) | 2022.04.07 |
---|---|
[Flutter] GetX를 사용해야할 이유3 - 종속성 관리(의존성 주입, 바인딩) (1) | 2022.04.07 |
[Flutter] GetX를 사용해야할 이유2 - 상태관리 (0) | 2022.04.06 |
[Flutter] GetX를 사용해야할 이유1 - Route (0) | 2022.04.06 |
[Flutter] 간단한 Flutter 권한 요청 라이브러리 사용 (with. permission_handler) (0) | 2022.04.04 |