JetpackCompose+MapComposeにPolylineを動的に追加する
前回は、MapComposeにMarkerを動的に追加しました。
今回は、Polylineを追加します。
まずは、地図上のタップ位置に対してPolylineを伸ばしていきます。
次に、スクリーン座標を地図座標表に変換してから、Polyline化していきます。
環境
AndroidStudio:Flamingo | 2022.2.1 Patch 2
OS:macOS
ライブラリは前回と一緒ですね。
implementation platform('androidx.compose:compose-bom:2022.10.00')
implementation 'androidx.compose.ui:ui'
implementation 'androidx.compose.ui:ui-graphics'
implementation 'androidx.compose.ui:ui-tooling-preview'
implementation 'androidx.compose.material3:material3'
implementation 'androidx.navigation:navigation-compose:2.7.0-beta01'
implementation platform('com.google.firebase:firebase-bom:32.1.1')
implementation 'com.google.maps.android:maps-compose:2.11.4'
implementation 'com.google.android.gms:play-services-maps:18.1.0'
Step1.Polylineを追加する
地図上のタップ位置をPolyline描画します。
まず、Polylineのpoints座標を保持するState定義を追加します。
Markerの時とは異なり、Stateの定義には「mutableStateOf」を使用します。
誤) val markerItems = remember { mutableStateListOf() }
正) var polylineItems by remember { mutableStateOf>(listOf()) }
var polylineItems by remember { mutableStateOf<List<LatLng>>(listOf()) }
次に、マップのonMapClickで一覧更新を行う記述を追加します。
GoogleMap(
modifier = modifier,
cameraPositionState = cameraPositionState,
onMapLoaded = onMapLoaded,
onMapClick = { latLng ->
polylineItems = polylineItems + latLng
},
) {
最後に、ポイントが2点以上となったらPolylineを描画するように記述します。
GoogleMap(/* ... */) {
/* ... */
if (polylineItems.count() > 1) {
Polyline(
points = polylineItems,
)
}
}
いざ実行
ここまでのコードはこちら
Step2.スクリーン座標を取得する
まず、スクリーンのタップ位置座標を取得するために、GoogleMapと同じ大きさ・同じ位置のBoxを配置します。
検証を目的にBoxを配置しています。
BoxをGoogleMapの上に配置することで、GoogleMapが拾っていたイベントをすべてBoxが取得するようになりますので、GoogleMapのズームやカメラ移動などは一切効かない状態になります。
Column {
Box(modifier = Modifier.weight(1f).fillMaxSize()) {
GoogleMap(
modifier = Modifier.matchParentSize(),
/* ... */
)
// GoogleMapと同じサイズ・位置のBox
Box(modifier = Modifier.matchParentSize())
}
Buttons(
modifier = Modifier.fillMaxWidth(),
/* ... */
)
}
GoogleMap()の下の行に追加したBoxが、タップイベントを拾うためのBoxです。
このBoxのmodifierにpointerInputを追加します。
Box(
modifier = Modifier
.matchParentSize()
.pointerInput(Unit) {
detectTapGestures(
onPress = { offset ->
if (!cameraPositionState.isMoving) {
val pressedLatLng = cameraPositionState.projection?.fromScreenLocation(Point(offset.x.toInt(), offset.y.toInt()))
if (pressedLatLng != null) {
polylineItems = polylineItems + pressedLatLng
}
}
},
)
},
)
cameraPositionState.projection?.fromScreenLocationがスクリーン座標と緯度経度の変換を行う関数です。