Framework/Flutter

[Flutter]Naver Map 사용하기

  • -
반응형

오늘은 Naver Map을 활용해 개발 중인 애플리케이션에 지도를 적용해 보았습니다.
작업 과정에서는 pub.dev의 flutter_naver_map 라이브러리를 참고했으며, 문서가 잘 정리되어 있어 해당 문서를 참고하시면 도움이 될 것입니다.

 

※ 테스트 환경
  • Flutter 3.22.3
  • Dart 3.5.4
  • flutter_naver_map 1.3.0

1. 어플리케이션 등록

1-1. Naver Map 사용 등록

NCP Console에 접속하여 Application을 등록합니다.

 

1-2. 네이버 지도 서비스 등록

Web Dynamic Map, Mobile Dynamic Map을 선택하고, Android, iOS 패키지명을 입력합니다.

 

1-3. Client ID 확인

 

 

2. Naver Map 위젯 만들기

2-1. 지도 초기화

.env 환경 변수에 생성된 Client ID를 등록합니다.

 

.env.local(.env)

NAVER_CLIENT_ID=클라이언트키 입력

 

앱의 시작점인 main() 함수에서 runApp이 실행되기 전 Naver Map을 초기화합니다. 여기서는 main() 함수에서 초기화를 했지만 정확하게는 지도 실행 전에 언제라도 상관이 없다고 가이드 문서에 명시되어 있습니다.

void main() async {
  WidgetsBinding widgetsBinding = WidgetsFlutterBinding.ensureInitialized();

  // 구성 파일 로드
  await dotenv.load(fileName: kDebugMode ? ".env.local" : ".env");

  // Naver Map 초기화
  await NaverMapSdk.instance.initialize(
      clientId: dotenv.get('NAVER_CLIENT_ID'),
      onAuthFailed: (error) {
        logger.e('Auth failed: $error');
      });

  runApp(const ProviderScope(child: MyApp()));
}

 

2-2. 지도 위젯 생성

지도를 어디서든 사용할 수 있게 공통 위젯으로 분리시켰습니다.

class MyNaverMap extends ConsumerStatefulWidget {
  final double addX;
  final double addY;

  const MyNaverMap({
    super.key,
    required this.addX,
    required this.addY,
  });
  @override
  ConsumerState<MyNaverMap> createState() => _WeddingMain();
}

class _WeddingMain extends ConsumerState<MyNaverMap> {
  NaverMapController? _mapController;

  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    final cameraUpdate = NCameraUpdate.withParams(
      target: NLatLng(widget.addY, widget.addX),
      zoom: 12,
      bearing: 0,
    );
    final marker =
        NMarker(id: 'test', position: NLatLng(widget.addY, widget.addX));

    // 지도 생성 이후 다시 호출되었을 때를 지도 좌표가 변경된 것으로 보고 마커와 위치를 이동시킨다.
    if (_mapController != null) {
      _mapController!.updateCamera(cameraUpdate);
      _mapController!.addOverlay(marker);
    }

    return Container(
        height: 250,
        margin: const EdgeInsets.only(top: 10),
        decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(borderRadiusRate),
          border: Border.all(
            width: 1.0,
            color: borderColor,
          ),
          color: basicBoxColor,
        ),
        child: NaverMap(
          options: NaverMapViewOptions(
            mapType: NMapType.basic,
            initialCameraPosition: NCameraPosition(
                target: NLatLng(widget.addY, widget.addX),
                zoom: 12,
                bearing: 0,
                tilt: 0),
          ),
          forceGesture: false,
          onMapReady: (controller) async {
            _mapController = controller;
            controller.addOverlay(marker);
          },
          onMapTapped: (point, latLng) {},
          onSymbolTapped: (symbol) {},
          onCameraChange: (position, reason) {},
          onCameraIdle: () {},
          onSelectedIndoorChanged: (indoor) {},
        ));
  }
}

 

addX(경도), addY(위도) 를 인자값으로 전달받아 NaverMapController를 통해 지도의 카메라, 마커 위치를 재조정할 수 있도록 했습니다.

최초 지도가 호출될 때(onMapReady 실행전)에는 _mapController가 null로 존재하기 때문에 initailCameraPosition을 통해 카메라 위치가 셋팅됩니다. onMayReady 이후에 마커가 표기 되며, 지도 위젯이 재호출 되는 경우 _mapController를 통해 인자값으로 전달받은 위도, 경도로 카메라 위치와 마커를 수정합니다.

if (_mapController != null) {
_mapController!.updateCamera(cameraUpdate); _mapController!.addOverlay(marker);
}

 

생성된 지도 위젯을 사용해보겠습니다.

Column(
  crossAxisAlignment: CrossAxisAlignment.start,
  children: [
    MyTextbox(textField: '주소', fontSize: fontSmallSize),
    Container(
      margin: const EdgeInsets.only(top: 5),
      child: Column(
        children: [
          Container(
            height: 45,
            color: widgetWhiteColor,
            child: TextField(
              controller: _addressController,
              readOnly: true,
              decoration: const InputDecoration(
                enabledBorder: OutlineInputBorder(
                  borderSide: BorderSide(color: borderColor, width: 1),
                  borderRadius: BorderRadius.all(
                      Radius.circular(borderRadiusRate)),
                ),
                border: OutlineInputBorder(
                  borderRadius: BorderRadius.all(
                      Radius.circular(borderRadiusRate)),
                ),
                contentPadding: EdgeInsets.only(
                  left: 10,
                ),
                hintStyle: TextStyle(
                  fontSize: fontMediumSize,
                  fontWeight: FontWeight.w500,
                  color: grayFontColor,
                ),
                hintText: '예식장 주소',
              ),
              style: const TextStyle(
                color: widgetBlackColor,
                fontSize: fontMediumSize,
                fontWeight: FontWeight.w600,
              ),
              onTap: () async {
                await showTopModalSheet<String?>(
                  context,
                  MapWebview(
                    saveMap: (String value) {
                      var data = jsonDecode(value);
                      logger.i(data);
                      String address = data['address'];
                      double addX = data['lng'];
                      double addY = data['lat'];

                      ref
                          .read(weddingProvider(widget.cardNo).notifier)
                          .updateAddress(address, addX, addY);
                    },
                  ),
                );
              },
            ),
          ),
          // 지도 영역
          MyNaverMap(
            addX: addX,
            addY: addY,
          ),
        ],
      ),
    ),
  ],
),

 

addX(경도), addY(위도)는 네이버 지도의 초기 위도, 경도값으로 초기화합니다. 

DB에 저장된 값을 통해 지도가 그려지고(없는 경우 초기값) TextField의 onTab을 통해 호출된 웹 뷰(네이버 맵, 주소 검색)를 통해 전달받은 위도, 경도로 지도를 다시 그려지게 설계했습니다.

 

 

3. 테스트

의도한 바와 같이 작동하는지 확인해봅니다.

 

예제에 사용된 옵션 외에도 다양한 옵션이 존재합니다. 본 예제에서는 기본적인 지도의 생성과 사용법에 대해 알아봤고, 추가적인 옵션과 사용법은 아래 문서를 통해 확인하시길 바랍니다.

 

참고문서
 

flutter_naver_map | Flutter package

Naver Map plugin for Flutter, which provides map service of Korea.

pub.dev

 

반응형
Contents

포스팅 주소를 복사했습니다.

이 글이 도움이 되었다면 공감 부탁드립니다.