-
Notifications
You must be signed in to change notification settings - Fork 142
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Add experimental MapEffect composable (#140)
* feat: Add experimental MapEffect composable Change-Id: I6612683d4c67d350dd0b66310e98108b564b73e3 * Update app/src/main/java/com/google/maps/android/compose/MapClusteringActivity.kt Co-authored-by: Sean Barbeau <sjbarbeau@gmail.com> * PR feedback. Change-Id: I84922456c00314ab3a622385accd088980fa0695 Co-authored-by: Sean Barbeau <sjbarbeau@gmail.com>
- Loading branch information
Showing
11 changed files
with
271 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
99 changes: 99 additions & 0 deletions
99
app/src/main/java/com/google/maps/android/compose/MapClusteringActivity.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
package com.google.maps.android.compose | ||
|
||
import android.os.Bundle | ||
import android.util.Log | ||
import androidx.activity.ComponentActivity | ||
import androidx.activity.compose.setContent | ||
import androidx.compose.foundation.layout.fillMaxSize | ||
import androidx.compose.runtime.Composable | ||
import androidx.compose.runtime.LaunchedEffect | ||
import androidx.compose.runtime.getValue | ||
import androidx.compose.runtime.mutableStateListOf | ||
import androidx.compose.runtime.mutableStateOf | ||
import androidx.compose.runtime.remember | ||
import androidx.compose.runtime.setValue | ||
import androidx.compose.ui.Modifier | ||
import androidx.compose.ui.platform.LocalContext | ||
import com.google.android.gms.maps.GoogleMap | ||
import com.google.android.gms.maps.model.CameraPosition | ||
import com.google.android.gms.maps.model.LatLng | ||
import com.google.maps.android.clustering.ClusterItem | ||
import com.google.maps.android.clustering.ClusterManager | ||
import kotlin.random.Random | ||
|
||
private val singapore = LatLng(1.35, 103.87) | ||
private val singapore2 = LatLng(2.50, 103.87) | ||
private val TAG = MapClusteringActivity::class.simpleName | ||
|
||
class MapClusteringActivity : ComponentActivity() { | ||
override fun onCreate(savedInstanceState: Bundle?) { | ||
super.onCreate(savedInstanceState) | ||
setContent { | ||
GoogleMapClustering() | ||
} | ||
} | ||
} | ||
|
||
@Composable | ||
fun GoogleMapClustering() { | ||
val items = remember { mutableStateListOf<MyItem>() } | ||
LaunchedEffect(Unit) { | ||
for (i in 1..10) { | ||
val position = LatLng( | ||
singapore2.latitude + Random.nextFloat(), | ||
singapore2.longitude + Random.nextFloat(), | ||
) | ||
items.add(MyItem(position, "Marker", "Snippet")) | ||
} | ||
} | ||
GoogleMapClustering(items = items) | ||
} | ||
|
||
@OptIn(MapsComposeExperimentalApi::class) | ||
@Composable | ||
fun GoogleMapClustering(items: List<MyItem>) { | ||
val cameraPositionState = rememberCameraPositionState { | ||
position = CameraPosition.fromLatLngZoom(singapore, 10f) | ||
} | ||
GoogleMap( | ||
modifier = Modifier.fillMaxSize(), | ||
cameraPositionState = cameraPositionState | ||
) { | ||
val context = LocalContext.current | ||
var clusterManager by remember { mutableStateOf<ClusterManager<MyItem>?>(null) } | ||
MapEffect(items) { map -> | ||
if (clusterManager == null) { | ||
clusterManager = ClusterManager<MyItem>(context, map) | ||
} | ||
clusterManager?.addItems(items) | ||
} | ||
LaunchedEffect(key1 = cameraPositionState.isMoving) { | ||
if (!cameraPositionState.isMoving) { | ||
clusterManager?.onCameraIdle() | ||
} | ||
} | ||
MarkerInfoWindow( | ||
state = rememberMarkerState(position = singapore), | ||
onClick = { | ||
// This won't work :( | ||
Log.d(TAG, "I cannot be clicked :( $it") | ||
true | ||
} | ||
) | ||
} | ||
} | ||
|
||
data class MyItem( | ||
val itemPosition: LatLng, | ||
val itemTitle: String, | ||
val itemSnippet: String, | ||
) : ClusterItem { | ||
override fun getPosition(): LatLng = | ||
itemPosition | ||
|
||
override fun getTitle(): String = | ||
itemTitle | ||
|
||
override fun getSnippet(): String = | ||
itemSnippet | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
96 changes: 96 additions & 0 deletions
96
maps-compose/src/main/java/com/google/maps/android/compose/MapEffect.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
package com.google.maps.android.compose | ||
|
||
import androidx.compose.runtime.Composable | ||
import androidx.compose.runtime.ExperimentalComposeApi | ||
import androidx.compose.runtime.LaunchedEffect | ||
import androidx.compose.runtime.currentComposer | ||
import com.google.android.gms.maps.GoogleMap | ||
import kotlinx.coroutines.CoroutineScope | ||
|
||
/** | ||
* A side-effect backed by a [LaunchedEffect] which will launch [block] and provide the underlying | ||
* managed [GoogleMap] object into the composition's [CoroutineContext]. This effect will be | ||
* re-launched when a different [key1] is provided. | ||
* | ||
* Note: This effect should be used with caution as the [GoogleMap]'s properties is managed by the | ||
* [_root_ide_package_.com.google.maps.android.compose.GoogleMap()] composable function. However, | ||
* there are use cases when obtaining a raw reference to the map is desirable for extensibility | ||
* (e.g. using the utility library for clustering). | ||
*/ | ||
@Composable | ||
@GoogleMapComposable | ||
@MapsComposeExperimentalApi | ||
public fun MapEffect(key1: Any?, block: suspend CoroutineScope.(GoogleMap) -> Unit) { | ||
val map = (currentComposer.applier as MapApplier).map | ||
LaunchedEffect(key1 = key1) { | ||
block(map) | ||
} | ||
} | ||
|
||
/** | ||
* A side-effect backed by a [LaunchedEffect] which will launch [block] and provide the underlying | ||
* managed [GoogleMap] object into the composition's [CoroutineContext]. This effect will be | ||
* re-launched when a different [key1] or [key2] is provided. | ||
* | ||
* Note: This effect should be used with caution as the [GoogleMap]'s properties is managed by the | ||
* [_root_ide_package_.com.google.maps.android.compose.GoogleMap()] composable function. However, | ||
* there are use cases when obtaining a raw reference to the map is desirable for extensibility | ||
* (e.g. using the utility library for clustering). | ||
*/ | ||
@Composable | ||
@GoogleMapComposable | ||
@MapsComposeExperimentalApi | ||
public fun MapEffect(key1: Any?, key2: Any?, block: suspend CoroutineScope.(GoogleMap) -> Unit) { | ||
val map = (currentComposer.applier as MapApplier).map | ||
LaunchedEffect(key1 = key1, key2 = key2) { | ||
block(map) | ||
} | ||
} | ||
|
||
/** | ||
* A side-effect backed by a [LaunchedEffect] which will launch [block] and provide the underlying | ||
* managed [GoogleMap] object into the composition's [CoroutineContext]. This effect will be | ||
* re-launched when a different [key1], [key2], or [key3] is provided. | ||
* | ||
* Note: This effect should be used with caution as the [GoogleMap]'s properties is managed by the | ||
* [_root_ide_package_.com.google.maps.android.compose.GoogleMap()] composable function. However, | ||
* there are use cases when obtaining a raw reference to the map is desirable for extensibility | ||
* (e.g. using the utility library for clustering). | ||
*/ | ||
@Composable | ||
@GoogleMapComposable | ||
@MapsComposeExperimentalApi | ||
public fun MapEffect( | ||
key1: Any?, | ||
key2: Any?, | ||
key3: Any?, | ||
block: suspend CoroutineScope.(GoogleMap) -> Unit | ||
) { | ||
val map = (currentComposer.applier as MapApplier).map | ||
LaunchedEffect(key1 = key1, key2 = key2, key3 = key3) { | ||
block(map) | ||
} | ||
} | ||
|
||
/** | ||
* A side-effect backed by a [LaunchedEffect] which will launch [block] and provide the underlying | ||
* managed [GoogleMap] object into the composition's [CoroutineContext]. This effect will be | ||
* re-launched with any different [keys]. | ||
* | ||
* Note: This effect should be used with caution as the [GoogleMap]'s properties is managed by the | ||
* [_root_ide_package_.com.google.maps.android.compose.GoogleMap()] composable function. However, | ||
* there are use cases when obtaining a raw reference to the map is desirable for extensibility | ||
* (e.g. using the utility library for clustering). | ||
*/ | ||
@Composable | ||
@GoogleMapComposable | ||
@MapsComposeExperimentalApi | ||
public fun MapEffect( | ||
vararg keys: Any?, | ||
block: suspend CoroutineScope.(GoogleMap) -> Unit | ||
) { | ||
val map = (currentComposer.applier as MapApplier).map | ||
LaunchedEffect(keys = keys) { | ||
block(map) | ||
} | ||
} |
13 changes: 13 additions & 0 deletions
13
maps-compose/src/main/java/com/google/maps/android/compose/MapsComposeExperimentalApi.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package com.google.maps.android.compose | ||
|
||
/** | ||
* Marks declarations that are still **experimental**. | ||
* | ||
*/ | ||
@MustBeDocumented | ||
@Retention(value = AnnotationRetention.BINARY) | ||
@RequiresOptIn( | ||
level = RequiresOptIn.Level.WARNING, | ||
message = "Targets marked by this annotation may contain breaking changes in the future as their design is still incubating." | ||
) | ||
public annotation class MapsComposeExperimentalApi |