Google Maps Compose:如何将Marker固定在屏幕中央且地图可拖拽?
实现固定在屏幕中央的Marker(地图拖拽时Marker不动)
核心思路
不要将Marker嵌入地图组件内部,而是把Marker作为独立UI元素叠加在地图的屏幕中央,同时监听地图相机位置的变化,实时获取当前地图中央的经纬度。
修改后的完整代码
@OptIn(ExperimentalMaterial3Api::class, ExperimentalPermissionsApi::class) @Composable fun MapScreen(navController: NavHostController) { val (addressQuery, setAddressQuery) = remember { mutableStateOf("") } val initialLocation = remember { mutableStateOf(LatLng(0.132828, 100.804833)) } val cameraPositionState = rememberCameraPositionState { position = CameraPosition.fromLatLngZoom(initialLocation.value, 15f) } // 保存当前地图中央的经纬度 val centerLatLng = remember { mutableStateOf(initialLocation.value) } val locationPermission = rememberMultiplePermissionsState( listOf(Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION) ) val uiSettings = MapUiSettings( compassEnabled = true, rotationGesturesEnabled = true, scrollGesturesEnabled = true, tiltGesturesEnabled = false, zoomControlsEnabled = false, zoomGesturesEnabled = true, mapToolbarEnabled = false, myLocationButtonEnabled = false, scrollGesturesEnabledDuringRotateOrZoom = true, indoorLevelPickerEnabled = true ) val mapProperties = MapProperties( maxZoomPreference = 15f, minZoomPreference = 1f, isTrafficEnabled = false, mapType = MapType.NORMAL, isMyLocationEnabled = locationPermission.allPermissionsGranted, ) val mapColorScheme = remember { mutableStateOf(ComposeMapColorScheme.FOLLOW_SYSTEM) } val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState()) // 监听相机位置变化,实时更新中央经纬度 LaunchedEffect(cameraPositionState.position) { centerLatLng.value = cameraPositionState.position.target // 这里可添加后续逻辑,比如根据经纬度获取地址 println("当前中央位置:${centerLatLng.value.latitude}, ${centerLatLng.value.longitude}") } Scaffold( modifier = Modifier.fillMaxSize(), floatingActionButton = { FloatingActionButton( onClick = { if (locationPermission.allPermissionsGranted) { cameraPositionState.position = CameraPosition.fromLatLngZoom(initialLocation.value, 15f) } else { locationPermission.launchMultiplePermissionRequest() } }, contentColor = if (locationPermission.allPermissionsGranted) LogoBlue else Gray ) { Icon( painter = painterResource(R.drawable.ic_gps), contentDescription = "校准到当前位置", tint = LogoBlue ) } }, topBar = { CenterAlignedTopAppBar( title = { Image( painter = painterResource(id = R.drawable.ic_pocket_small), contentDescription = null ) }, colors = TopAppBarDefaults.centerAlignedTopAppBarColors( containerColor = MaterialTheme.colorScheme.primaryContainer, titleContentColor = MaterialTheme.colorScheme.onPrimary, ), navigationIcon = { IconButton(onClick = { navController.navigateUp() }) { Icon( imageVector = Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "返回箭头", tint = MaterialTheme.colorScheme.onPrimary ) } }, scrollBehavior = scrollBehavior ) } ) { paddingValues -> if (locationPermission.allPermissionsGranted) { LocationFetcher { location, string -> location?.let { initialLocation.value = LatLng(it.latitude, it.longitude) cameraPositionState.position = CameraPosition.fromLatLngZoom(LatLng(it.latitude, it.longitude), 15f) } } } Box(Modifier.padding(top = paddingValues.calculateTopPadding())) { GoogleMap( modifier = Modifier.fillMaxSize(), cameraPositionState = cameraPositionState, mapColorScheme = mapColorScheme.value, uiSettings = uiSettings, properties = mapProperties, ) { // 移除原地图内的MarkerComposable } // 叠加在地图中央的Marker UI Column( Modifier.fillMaxSize(), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center ) { // 替换为你的自定义Marker图标或Composable Icon( painter = painterResource(R.drawable.ic_marker), contentDescription = "中央标记", tint = Color.Red, modifier = Modifier.size(48.dp) ) } // 原有搜索视图 Column( Modifier.fillMaxSize(), horizontalAlignment = Alignment.CenterHorizontally ) { CustomSearchView( addressQuery, onValueChange = { println(it) setAddressQuery(it) }) { addressList() } } } } }
关键修改点说明
- 移除地图内的Marker:原
MarkerComposable会跟随地图移动,不符合需求,直接移除。 - 固定中央UI元素:在
Box中添加居中布局的Marker图标,这个元素不受地图拖拽影响,始终停留在屏幕中央。 - 监听相机位置:通过
LaunchedEffect监听cameraPositionState.position变化,相机的target属性就是当前屏幕中央的经纬度,将其保存到centerLatLng状态中,可用于后续地址解析等操作。 - 状态优化:用
centerLatLng变量专门保存中央位置的经纬度,替代原marker变量。
此方案实现了类似Uber/Ola的选点逻辑:拖拽地图时Marker视觉上固定,同时能实时获取该位置的经纬度。
内容的提问来源于stack exchange,提问作者Sanjay
相关产品推荐
相关产品推荐

