[Flutter] 구글맵에서 위젯으로 마커 그리기

Seong-Am Kim
6 min readApr 16, 2022

위치기반 서비스를 제작한다고 한다면 마커는 필수적인 요소 중 하나이다.

대부분 기본으로 제공 되는 마커를 이용하기 보다 디자인된 마커를 구현해야 하는데 생각보다 이를 구현하는 부분이 쉽지가 않다.

이는 구글 맵 패키지가 지원하는 부분이 위젯이 아니라 BitmapDescriptor (비트맵 이미지)를 지원하기 때문인데 이미지만을 가지고 마커를 그리는 것은 다른 글들도 많이 있으니 해당 글에선 위젯을 가지고 마커를 만드는 방법에 대해 살펴보려고 한다.

Photo by GeoJango Maps on Unsplash

해당 글은 아래와 같은 순서로 진행된다.

  1. 마커를 구현 하는 전체적인 과정
  2. 마커 위젯 생성
  3. 마커 이미지 랜더링
  4. 마커 위젯을 비트맵 이미지로 변환
  5. 구현된 마커를 지도에 반영하는 방법

google_maps_flutter 패키지를 이용함을 전제로 하며 2.1.1 버전을 이용하였으니 참고 바란다.

1. 마커를 구현 하는 전체적인 과정

앞서 이야기 했듯이 google_maps_flutter 패키지는 마커에 관하여 비트맵 이미지를 지원하고 있다. 이를 위해 위젯을 이미지화 하는 작업이 필요하다.

전체적인 과정을 살펴 보면 아래와 같다.

google_maps_flutter에서 요구하는 BitmapDescriptor을 제공하는 것을 목표로 한다.

2.마커 위젯 생성

첫번째로, 실제 지도에 반영할 마커 위젯을 생성해보자. 이는 각자 환경에 맞게 위젯을 생성하며 된다.

여기에 기본 위젯과 더하여 나중에 비트맵으로 변경하기 위해여 몇 가지 작업을 추가해줘야 한다.

여기서 중요한 부분은 마커가 실제 빌드가 되어야 비트맵 이미지를 가져오는 것이 가능하다.

우선 코드 부터 살펴보자.

위에서 _renderAMarker()가 실제 구현된 위젯이며 위의 예제에선 들어온 타입에 따라 각기 다른 마커를 랜더링 시킨다.

여기서 중요한 부분은 RepaintBoundary 위젯인데 이는 렌더링 할때 별도의 표시 목록을 생성해서 글로벌 키를 통해 해당 위젯을 가져올 수 있게 한다.

쉽게 말하자면 나중에 위젯을 가져와 이미지로 변환할때 위젯을 가져 올 수 있게 하기 위해 해당 위젯과 함께 글로벌 키가 필요하다는 이야기다.

여기서 키는 Flutter에서 랜더링 할때 새롭게 랜더링할 요소를 정하는 중요한 부분중 하나인데 이에 대해 설명하는 것은 논제에서 벗어나므로 추후 기회가 되면 따로 다루도록 하겠다.

또 하나의 주목해야 되는 부분은 initState에 등록된 addPostFrameCallback 이다. 해당 콜백은 build가 끝난 시점에서 호출이 된다.

해당 콜백이 필요한 이유는 실제 화면에 마커가 랜더링 된 이후에 이미지를 가져올 수 있는데 이를 위해선 build가 끝난 시점이야 하기 때문이다.

하지만 실제 구현했을 땐 addPostFrameCallback 이후에 일정 시간 짧은 딜레이가 필요했는데 이에 대한 정확한 이유는 모르겠으나 프레임이 진행 중이라 addPostFrameCallback 에서 딜레이 없이 바로 가져왔을때 가져오는게 불가능 했던 것이라 예상하고 있다.

이후 onFinishRendering 함수를 통해 마커의 랜더링이 모두 완료됐음을 알려준다.

3. 마커 위젯 랜더링

앞서 이야기 했듯이 마커의 랜더링이 완료가 되어야 이미지로 변환이 가능한데 이를 위해선 실제 화면에 마커를 랜더링 시켜야 한다.

여기서 약간의 요령이 필요한데 Stack을 이용하여 실제 유저는 마커를 보지 못하게 필요한 마커들을 화면의 뒷부분에 배치 해준다.

예를 들면 아래 코드 처럼 할 수 있다.

...@override
Widget build(BuildContext context) {
return Stack(
children: [
ExhibitionMarker(
type: MarkerType.exhibition,
onFinishRendering: _setMarkerIcons,
),
Scaffold(
body: ...
) ] )}

4. 마커 위젯을 비트맵 이미지로 변환

이제 랜더링된 마커 위젯을 비트맵 이미지로 변환 해주면 된다.

위의 예에선 onFinishRendering 에 등록된 콜백에서 이미지로의 변환을 위한 로직들을 구현해주면 된다.

랜더링된 마커를 찾기 위해선 Global key가 필요하다. onFinishRendering 에서 Global key인자를 전달해주는 것도 이때문이며 Global key를 통해 위젯 트리에서 마커트리를 찾을 수 있기 때문이다.

위의 함수는 위젯을 PNG로 변환해주는 함수이며 이를 통해 목표로 이미지를 얻을 수 있다.

5. 구현된 마커를 지도에 반영하는 방법

위의 과정을 통해 BitmapDescriptor를 획득을 하였으면 이제 실제 마커를 구글 지도에 반영하는 것은 일반 마커를 반영하는 것과 동일하므로 어렵지 않다.

google_map_package 에서는 Marker 객체를 통해 마커를 등록 하도록 하고 있다.

icon에 위에서 얻은 BitmapDescriptor을 넣어준다.

Set<Marker> _markers = {}...void addTheMarker() {
setState(() {
_markers.add(
Marker(
...
icon: _marker
...
) )
});
}@override
Widget build(BuildContext context) {
return GoogleMap(
markers: _markers,
)
}

GoogleMap 위젯에 markers를 등록하게 되면 아래 처럼 마커들이 표시되는 것을 볼 수 가 있다.

글을 마무리 하며

이미지만을 이용하여 마커를 구현해야 한다면 사실 위의 과정이 필요 없이 바로 BitmapDescriptor를 이용하여 구현하면 된다.

하지만 이미지만으로는 마커를 구현할때는 여러 제한 사항이 있다.

동적으로 마커의 텍스트가 변화해야 되는등, 마커마다 다른 모양이 적용되야 하는 경우에는 일일이 적용이 불가능 하므로 위의 방법을 통하면 이를 해결 할 수가 있다.

--

--