이번 포스트에서는 여러 앱에서 내 위치를 선택할 때 사용하는 마커(핀) 인터렉션에 대해 알아보려고 한다.
지도를 사용하는 앱은 굉장히 많고, 많은 앱들에서 현재 위치를 선택할 수 있는 기능을 제공한다.
현재 위치를 선택하는 화면에는 어떤 인터렉션이 숨어있을까?
많은 앱이 있겠지만 쏘카와 배달의민족 이미지를 준비했다.
쏘카에서 내 위치를 선택하는 핀
배달의민족에서 내 위치를 선택하는 핀
기능적으로 보면 두 앱에서는 동일하게 본인의 위치를 선택하는 기능을 한다.
다른 점이 있다면, 쏘카는 한강에 위치하게 될 경우 비활성화되고, 배달의 민족에서는 작업처리하는 과정을 사용자에게 노출한다. (ProgressBar)
..
그렇다면 위의 인터렉션은 어떻게 개발할까?.
천천히 시작해보자.
앞서 본 두 경우에서는 사용자의 터치에의해 Google Map이 이동하는 동안은 마커가 위로 올라가는 것을 볼 수 있다.
위로 올라가 있는 동안에도 위치를 정확하게 맞출 수 있게 마커의 그림자를 표시해 두었는데, 나는 이 그림자를 좀 더 입체적으로 표현해볼까 한다. (그림자로 주는 원근감)
구현해볼 사항을 정리해 보면 다음과 같다.
먼저 Flutter에서 구글 맵을 사용하기 위해서는 다음 패키지를 불러와야한다.
google_maps_flutter: ^2.0.6
GoogleMap(),
GoogleMap
위젯을 사용하여 간단하게 화면에 지도를 출력할 수 있다.
마커를 움직이기 위해서 구글 맵의 이벤트를 달아야한다.
구글 맵 터치 이벤트의 시작과 끝을 알아야한다.
GoogleMap(
onCameraIdle: () {
// 카메라 이동이 멈춘 경우
},
onCameraMoveStarted: () {
// (사용자에 의해)카메라 이동이 시작된 경우
},
...
),
위의 두 함수를 통해서 이벤트를 감지할 수 있다.
그렇다면 마커에게 움직임을 주기 위해서는..
onCameraMoveStarted
상황에 마커의 애니메이션을 시작하고,
onCameraIdle
에 마커의 애니메이션을 종료하면 된다.
구글 맵 위에서 마커를 띄우기 위해서는 아래와 같이 마커를 만들어 줘야한다.
canvas나 image를 사용한다.
GoogleMap(
markers: _markers,
),
하지만, 이 경우에는 본인의 위치를 화면의 정중앙에 위치하도록 하는 상황이기 때문에 마커를 만들지 않아도 된다.
그렇기 때문에 아래의 코드와 같이 Stack으로 쌓은 위젯트리 내부에 마커위젯으로 구현해도 된다.
Stack(
children: [
GoogleMapWidget(),
MarkerWidget(), // == AnimatedMarker()
...
],
...
),
위젯으로 마커를 구현한다고하면 구현 난이도가 훨씬 낮아지게 된다.
먼저 위에서 설명한 구글 맵의 함수를 먼저 채워 넣는다.
bool isMove = false;
///
GoogleMap(
onCameraIdle: () {
// 카메라 이동이 멈춘 경우
setState(()=> isMove = false);
},
onCameraMoveStarted: () {
// (사용자에 의해)카메라 이동이 시작된 경우
setState(()=> isMove = true);
},
...
),
...
이후 마커를 구현하는데 움직일 때 투명해지는 모습은 AnimatedOpacity
위젯을 사용하고, 위치 변화/그림자 효과는 AnimatedContainer
를 사용할 것이다.
사용자의 터치 이벤트를 받게 되면, 마커가 공중으로 뜬 것처럼 보이게 된다.
또한, 마커의 그림자가 커지는 듯한 모습을 구현했다.
그림자의 모양은 Radius.elliptical()
를 적용하여 타원형을 만들었다.
class AnimatedMarker extends StatelessWidget {
final bool isMoving;
const AnimatedMarker({Key? key, this.isMoving = false}) : super(key: key);
Widget build(BuildContext context) {
return Align(
alignment: Alignment.center,
child: SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
AnimatedOpacity(
opacity: this.isMoving ? 0.5 : 1,
child: MyMarker(),
),
/// 그림자 및 높이 조절 위젯
AnimatedContainer(
duration: const Duration(milliseconds: 150),
decoration: BoxDecoration(
borderRadius: const BorderRadius.all(Radius.elliptical(100, 50)),
gradient: RadialGradient(
colors: gradientColors,
radius: 1.2,
),
),
height: this.isMoving ? 6 : 3,
width: this.isMoving ? 16 : 8,
margin: EdgeInsets.only(
top: this.isMoving ? 16 : 0,
bottom: this.isMoving ? 16 + 48 : 48,
),
),
],
),
),
);
}
}
❗️ 화면에 구현된 모습에 따라, SafeArea와 Align을 적절히 사용해 실제 화면의 중앙과 마커의 위치를 일치시키도록 하자.
위의 코드를 사용하여 아래 이미지와 같은 결과물을 만들어 낼 수 있다.
이번 경우에는 화면의 중앙에 핀이 있어야한다는 조건 때문에 쉽게 구현할 수 있었다.
해당 인터렉션은 https://kilom.page.link/download (앱)을 다운 받아 확인할 수 있어요.
좀 더 궁금하시다면, 댓글을 남겨주세요!
안녕하세요 플러터 공부중인 대학생입니다! 구글 api로 마커 이동을 구현하고 싶은데 풀 코드가 궁금합니다 ㅠㅠ