Интеграция Google Maps в приложение Jetpack Compose

В статье мы поговорим о том, как интегрировать карты в приложение Jetpack Compose. Для этой цели потребуется библиотека Maps Compose.

Согласно официальной документации, библиотека Maps Compose содержит компонуемые функции и типы данных, позволяющие выполнять множество типовых задач.

Шаг 1. Получаем ключ API, следуя инструкциям по ссылке

Шаг 2. Включаем требуемые зависимости: 

implementation 'com.google.maps.android:maps-compose:2.7.2'
implementation 'com.google.android.gms:play-services-maps:18.1.0'

Примечание. Следует проверить, существует ли новые версии этих зависимостей.

Шаг 3. Добавляем метаданные в файл манифеста:

<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="${MAPS_API_KEY}" />

Все готово для реализации карт в коде!

Интеграция карт в приложение

Мы планируем показывать карты в приложении, вызывая GoogleMap(). Вот такое простое решение! GoogleMap  —  это компонуемый контейнер для MapView, позволяющий отображать карты в приложении. Мы можем передавать множество параметров в функцию GoogleMap(), но все они необязательные.

Перечислим некоторые из параметров.

  • cameraPositionState: CameraPositionState используется для управления состоянием камеры карты и наблюдения за ним.
  • googleMapOptionsFactory: () -> GoogleMapOptions  —  блок для создания GoogleMapOptions, предоставляемых при создании карты. 
  • properties: MapProperties  —  свойства карты, например isBuildingEnabled, isIndoorEnabled, isMyLocationEnabled и т.д. Если isMyLocationEnabled установлено в значение true, то необходимо запросить разрешение для определения точного и приближенного местоположения. 
  • uiSettings: MapUiSettings  —  настройки UI на карте, а именно compassEnabled, scrollGesturesEnabled, rotationGesturesEnabled и т.д. 
  • Различные лямбда-функции, например onMapClicked, onMapLoaded и onMyLocationButtonClick.

Мы можем настроить состояние камеры для увеличения масштаба определенного местоположения:

val cameraPositionState = rememberCameraPositionState {
position = CameraPosition.fromLatLngZoom(LatLng(44.810058, 20.4617586), 16f)
}

Кроме того, предоставляется возможность получить последнее или текущее местоположение. Более подробная информация по этому вопросу представлена в следующей документации.

Маркеры

Представим, что нам нужно отметить на карте места, например ближайшие заправки и гостиницы. Для таких случаев библиотека предоставляет Markers

Компонуемая функция Marker имеет несколько параметров. Здесь мы рассмотрим наиболее часто встречающиеся, но в дальнейшем желательно ознакомиться со всеми из них.

  • state: MarkerState используется для управления состоянием маркера и наблюдения за ним, например его положением и информационным окном.
  • draggable: Boolean устанавливает способность перемещения маркера. 
  • flat: Boolean определяет, должен ли маркер быть плоским по отношению к карте. 
  • icon: BitmapDescriptor устанавливает значок для маркера. 
  • Различные лямбда-функции, например onClick, onInfoWindowClick, onInfoWindowClose и onInfoWindowLongClick.

Добавляем несколько маркеров разных цветов. Пример кода: 

@Composable
fun GoogleMarkers() {
Marker(
state = rememberMarkerState(position = LatLng(44.811058, 20.4617586)),
title = "Marker1",
icon = BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED)
)
Marker(
state = rememberMarkerState(position = LatLng(44.811058, 20.4627586)),
title = "Marker2",
icon = BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_ORANGE)
)
Marker(
state = rememberMarkerState(position = LatLng(44.810058, 20.4627586)),
title = "Marker3",
icon = BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_YELLOW)
)
Marker(
state = rememberMarkerState(position = LatLng(44.809058, 20.4627586)),
title = "Marker4",
icon = BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_GREEN)
)
Marker(
state = rememberMarkerState(position = LatLng(44.809058, 20.4617586)),
title = "Marker5",
icon = BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_CYAN)
)
}

Получить значок маркера можно из актива (англ. asset), ресурса, растрового изображения, файла и т.д. При нажатии на любой из маркеров появляется информационное окно с его названием. 

Полилинии 

Предположим, что нужно нарисовать линию между точками. Эта задача решается с помощью компонуемой функции Polyline.

У нее только один обязательный параметр, а именно список значений широты и долготы. Перечислим ряд других параметров: 

  • clickable: Boolean  —  логическое значение. Оно показывает, активируется ли полилиния нажатием. 
  • color: Color  —  цвет полилинии. 
  • startCap: Cap  —  начальная верхняя точка полилинии. 
  • endCap: Cap  —  конечная нижняя точка полилинии. 
  • width: Float  —  ширина полилинии в пикселях экрана. 
  • onClick: (Polyline) -> Unit  —  лямбда, вызываемая при нажатии полилинии. 

Добавляем одну Polyline для соединения маркеров: 

Polyline(
points = listOf(
LatLng(44.811058, 20.4617586),
LatLng(44.811058, 20.4627586),
LatLng(44.810058, 20.4627586),
LatLng(44.809058, 20.4627586),
LatLng(44.809058, 20.4617586)
)
)

Итоговый вариант кода выглядит так:

@OptIn(ExperimentalPermissionsApi::class)
@Composable
fun MainScreen() {
val multiplePermissionState = rememberMultiplePermissionsState(
permissions = listOf(
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION
)
)
val cameraPositionState = rememberCameraPositionState {
position = CameraPosition.fromLatLngZoom(LatLng(44.810058, 20.4617586), 17f)
}

LaunchedEffect(Unit) {
multiplePermissionState.launchMultiplePermissionRequest()
}

MediumReposTheme {
Column(
modifier = Modifier
.fillMaxSize()
.background(MaterialTheme.colors.background)
.padding(16.dp)
) {
Text(
text = "Welcome to the MapsApp!",
style = MaterialTheme.typography.h5,
modifier = Modifier.fillMaxWidth(),
textAlign = TextAlign.Center
)
Spacer(modifier = Modifier.height(32.dp))
PermissionsRequired(
multiplePermissionsState = multiplePermissionState,
permissionsNotGrantedContent = { /* ... */ },
permissionsNotAvailableContent = { /* ... */ }
) {
GoogleMap(
cameraPositionState = cameraPositionState,
modifier = Modifier.weight(1f),
properties = MapProperties(isMyLocationEnabled = true),
uiSettings = MapUiSettings(compassEnabled = true)
) {
GoogleMarkers()
Polyline(
points = listOf(
LatLng(44.811058, 20.4617586),
LatLng(44.811058, 20.4627586),
LatLng(44.810058, 20.4627586),
LatLng(44.809058, 20.4627586),
LatLng(44.809058, 20.4617586)
)
)
}
}
}
}
}

@Composable
fun GoogleMarkers() {
Marker(
state = rememberMarkerState(position = LatLng(44.811058, 20.4617586)),
title = "Marker1",
icon = BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED)
)
Marker(
state = rememberMarkerState(position = LatLng(44.811058, 20.4627586)),
title = "Marker2",
icon = BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_ORANGE)
)
Marker(
state = rememberMarkerState(position = LatLng(44.810058, 20.4627586)),
title = "Marker3",
icon = BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_YELLOW)
)
Marker(
state = rememberMarkerState(position = LatLng(44.809058, 20.4627586)),
title = "Marker4",
icon = BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_GREEN)
)
Marker(
state = rememberMarkerState(position = LatLng(44.809058, 20.4617586)),
title = "Marker5",
icon = BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_CYAN)
)
}

Для работы с картами существует много разных параметров и компонуемых функций, но в рамках данной статьи мы их рассматривать не будем. Все они подробно описаны в официальной документации, с которой вы можете ознакомиться. 

На этом завершаем разговор о MapsApp. Полный вариант исходного кода предоставлен в репозитории GitHub

Читайте также:

Читайте нас в TelegramVK и Дзен


Перевод статьи Igor Stevanovic: Integrate Google Maps Into the Jetpack Compose App

Предыдущая статья7 советов по очистке кода React
Следующая статьяВспомнить все: 6 уникальных, но подзабытых утилит Linux