googlemaps / android-maps-compose

Jetpack Compose composables for the Maps SDK for Android
https://developers.google.com/maps/documentation/android-sdk/maps-compose
Apache License 2.0
1.16k stars 139 forks source link

MarkerState.showInfoWindow() not working after states are changed #196

Open thomaslang1912 opened 2 years ago

thomaslang1912 commented 2 years ago

I created a map with some markers on it:

GoogleMap(
    modifier = Modifier.matchParentSize(),
    cameraPositionState = cameraPositionState,
    uiSettings = mapUiSettings,
    onMapClick = {
    },
) {
    model.markerStates.forEachIndexed { index, markerState ->
        MarkerInfoWindowContent(
            state = markerState,
            title = "Match Marker",
            draggable = true,
        ) {
            Text("Home $index : Away $index", color = Color.Red)
        }
    }
}

The markerStates are stored within the model in variable markerStates:

class MapModel : ViewModel() {
    val markerStates = mutableStateListOf<MarkerState>()
    var uiSelectedMatchIndex = mutableStateOf<Int>(-1)
    val aroundMode = mutableStateOf<Int>(0)

    fun nextMatch() {
        if (markerStates.size <= 1)
            return
        if (uiSelectedMatchIndex.value < markerStates.size - 1)
            uiSelectedMatchIndex.value++
        else
            uiSelectedMatchIndex.value = 0
    }
}

On the map I added a button. On click it iterates the marker states and shows the info window:

IconButton(
    onClick = {
        model.nextMatch()
        if (model.uiSelectedMatchIndex.value > -1) {
            model.markerStates[model.uiSelectedMatchIndex.value].showInfoWindow()
        }
    }
) {
    Icon(
        Icons.Outlined.KeyboardArrowRight,
        contentDescription = ""
    )
}

This works fine. Now I added a button which replaces the states in the model with new ones:

IconButton(
    onClick = {
        model.markerStates.clear()
        markerStates.addAll(nearbyMarkers())
        model.markerStates[model.uiSelectedMatchIndex.value].showInfoWindow()
    },
) {
    Icon(
        Icons.Outlined.AccountCircle,
        contentDescription = ""
    )
}

When I press this button, the new markers are displayed on the map and the first infoWindow is displayed. All following clicks on next have no effect. Always the same InfoWindow is displayed. In debug mode I saw that iteration of markerStates works correct.

Environment details

project gradle

buildscript {
    ext {
        ext.kotlin_version = '1.7.10'
        ext.compose_compiler_version = '1.2.0'
        ext.compose_version = '1.2.0-rc03'
    }
}
plugins {
    id 'com.android.application' version '7.2.2' apply false
    id 'com.android.library' version '7.2.2' apply false
    id 'org.jetbrains.kotlin.android' version '1.7.10' apply false
}

module gradle

android {
    compileSdk 32

    defaultConfig {
        applicationId "com.example.markerstatebug"
        minSdk 30
        targetSdk 32
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        vectorDrawables {
            useSupportLibrary true
        }
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    kotlinOptions {
        jvmTarget = '1.8'
    }
    buildFeatures {
        compose true
    }
    composeOptions {
        kotlinCompilerExtensionVersion "1.3.0"//compose_version
    }
    packagingOptions {
        resources {
            excludes += '/META-INF/{AL2.0,LGPL2.1}'
        }
    }
}

dependencies {

    implementation 'androidx.activity:activity-compose:1.5.1'
    implementation "androidx.compose.foundation:foundation:$compose_version"
    implementation "androidx.compose.material:material:$compose_version"
    implementation 'androidx.core:core-ktx:1.8.0'
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation "androidx.compose.ui:ui:$compose_version"
    implementation "androidx.compose.ui:ui-tooling-preview:$compose_version"
    implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.5.1'
    implementation "androidx.compose.ui:ui-tooling-preview:1.2.1"
    implementation "androidx.compose.runtime:runtime-livedata:1.2.1"
    implementation "androidx.compose.ui:ui-tooling:1.2.1"

    implementation "com.google.maps.android:maps-compose:2.2.1"
    implementation 'com.google.android.gms:play-services-maps:18.1.0'
    implementation 'com.google.android.material:material:1.6.1'
    implementation 'com.google.maps.android:maps-ktx:3.4.0'
    implementation 'com.google.maps.android:android-maps-utils:2.3.0'

    testImplementation 'junit:junit:4.13.2'
    androidTestImplementation 'androidx.test.ext:junit:1.1.3'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
    androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version"
    debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"
    debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_version"
}
arriolac commented 2 years ago

@thomaslang1912 can you share the implementation of nearbyMarkers()?

thomaslang1912 commented 2 years ago

Hi Chris, to keep it simple I used the following implementation for showing the bug:

val list1 = listOf( MarkerState( LatLng(48.218967, 11.623746) ), MarkerState( LatLng(48.218967, 11.663746) ) )

val list2 = listOf( MarkerState( LatLng(48.238967, 11.623746) ), MarkerState( LatLng(48.258967, 11.623746) ) )

fun initialMarkers(): List { return list1 }

fun nearbyMarkers(): List { return list2 }

Best regards,

Thomas

cmota commented 2 years ago

hello @thomaslang1912 ,

I've had a similar issue here, that I was able to solve by using rememberMarkerState.

thomaslang1912 commented 1 year ago

Hi Carlos, using rememberMarkerState has no effect. As soon as the list of markers is changed showInfoWindow is not working anymore... @arriolac will there be a fix in future?

cmota commented 1 year ago

Hello @thomaslang1912,

I've used that approach and it worked. I don't have the project here right now, but I can attach a snippet next week.

PranayHousing commented 1 year ago

Try Marker window info instead with MarkerState

MarkerInfoWindow(
                        state = MarkerState(position = position),
                        onClick = {

                            if (currentMarkerInfoWindow.position == it.position) {
                                it.hideInfoWindow()
                                currentMarkerInfoWindow.position = LatLng(0.00, 0.00)
                            } else {
                                it.showInfoWindow()
                                currentMarkerInfoWindow.position = it.position
                            }

                            true
                        },
                        content = {...}
RowanG1 commented 1 month ago

What worked for me, is whenever the marker data changes on the map, just refresh the entire map. So: key(yourMarkerDataChangeTrigger) { GoogleMap(....) }