Implementing Google Places AutoComplete TextField in Jetpack Compose

Implementing Google Places AutoComplete TextField in Jetpack Compose

This article guides you through implementing Google Places AutoComplete functionality in your Jetpack Compose Android application.

1. Project Setup

Before diving into the implementation, ensure your project has the necessary dependencies:

  • Google Places SDK for Android: Add the following dependency to your build.gradle (Module:app) file:
implementation "com.google.android.libraries.maps:maps-compose:3.0.0" // Replace with your desired version
  • Jetpack Compose UI: Make sure you’re using the latest Jetpack Compose version. Refer to the official documentation for installation instructions.

2. Obtain API Keys

  • Google Maps Platform: Visit https://cloud.google.com/maps-platform and create a project if you don’t have one.
  • Enable APIs: Enable the “Google Maps Places API” and “Google Maps SDK for Android” from the “APIs & Services” section of your project.
  • API Key: Generate an API key for your project. Keep this key secure. Store it in a separate file or environment variable for security reasons.

3. Implement the AutoComplete TextField

Let’s create the basic structure of the composable function responsible for displaying and managing the Google Places AutoComplete:

@Composable
fun GooglePlacesAutoCompleteTextField(
    onPlaceSelected: (Place) -> Unit,
    initialQuery: String = ""
) {
    val context = LocalContext.current
    val placesClient = remember { Places.createClient(context) }
    val state = remember { AutoCompleteState(placesClient, initialQuery) }
    
    TextField(
        value = state.query,
        onValueChange = { query -> state.setQuery(query) },
        label = { Text("Enter a location") },
        modifier = Modifier.fillMaxWidth()
    )

    LaunchedEffect(key1 = state.query) {
        if (state.query.isNotBlank()) {
            state.predictions = state.placesClient.findAutocompletePredictions(
                FindAutocompletePredictionsRequest.newInstance(state.query, state.bounds)
            ).await()
        }
    }

    // Display suggestions/predictions
    if (state.predictions.isNotEmpty()) {
        Column {
            state.predictions.forEach { prediction ->
                Text(
                    text = prediction.place.name,
                    modifier = Modifier
                        .fillMaxWidth()
                        .clickable {
                            onPlaceSelected(prediction.place)
                            // Reset query
                            state.setQuery("")
                        }
                        .padding(vertical = 8.dp)
                )
            }
        }
    }
}

@Composable
fun AutoCompleteState(placesClient: PlacesClient, initialQuery: String) {
    var query by remember { mutableStateOf(initialQuery) }
    var predictions by remember { mutableStateOf>(emptyList()) }
    var bounds by remember { mutableStateOf(LatLngBounds.builder().build()) }

    fun setQuery(newQuery: String) {
        query = newQuery
    }

    // Update bounds based on location or user's search
    // Example: Update bounds on user's location
    if (state.location != null) {
        val southwest = LatLng(state.location.latitude - 0.5, state.location.longitude - 0.5)
        val northeast = LatLng(state.location.latitude + 0.5, state.location.longitude + 0.5)
        bounds = LatLngBounds.builder()
            .include(southwest)
            .include(northeast)
            .build()
    }
}

4. Explanations

Let’s break down the key elements of this composable function:

  • placesClient: This object is created using the Google Places API client and is used for making API requests.
  • state: This represents the state of the AutoComplete component, including the current query, predictions, and other relevant data.
  • TextField: We use Jetpack Compose’s TextField composable to display the input field where the user can type their location.
  • LaunchedEffect: When the user starts typing, this block triggers an API call to fetch autocomplete predictions based on the current query.
  • predictions: This variable holds the list of autocomplete predictions returned by the API.
  • Column: A column is used to display the list of predictions below the input field.
  • Text: Each prediction is displayed as a text item, making it clickable.
  • onPlaceSelected: When the user selects a prediction, this callback function is executed with the selected Place object.

5. Integrating the AutoComplete TextField

Now, you can easily integrate the GooglePlacesAutoCompleteTextField composable into your UI:

@Composable
fun HomeScreen() {
    var selectedPlace by remember { mutableStateOf(null) }

    Column(modifier = Modifier.padding(16.dp)) {
        GooglePlacesAutoCompleteTextField(
            onPlaceSelected = { place ->
                selectedPlace = place
            },
            initialQuery = "Initial location" // Optional: Set an initial query
        )
        if (selectedPlace != null) {
            Text("Selected Place: ${selectedPlace?.name}")
        }
    }
}

6. Handling Permissions

Ensure your application requests necessary permissions:

  • AndroidManifest.xml: Add the following permissions in your app’s AndroidManifest.xml file:



7. Considerations

  • Location Services: To enhance the accuracy of suggestions, consider enabling location services and requesting the user’s location.
  • Error Handling: Implement robust error handling mechanisms to gracefully handle network issues or API errors.
  • Performance: Be mindful of the number of predictions displayed and the potential impact on UI responsiveness.
  • Customization: Explore options to further customize the styling of the AutoComplete TextField and predictions. Use Jetpack Compose modifiers to achieve the desired appearance.


Leave a Reply

Your email address will not be published. Required fields are marked *