You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Google Maps Flutter:设置上下内边距后精准获取地图中心坐标

如何精准获取设置内边距后的Google Map中心坐标

已知无上下内边距时,Google Map的中心坐标为LatLng(37.7749, -122.4194),当给地图设置顶部内边距50.0px、底部内边距200.0px后,当前通过计算经纬度偏移的方式实现,但精度不足,相关代码如下:

import 'dart:async';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MapSample(),
    );
  }
}

class MapSample extends StatefulWidget {
  const MapSample({Key? key}) : super(key: key);

  @override
  State<MapSample> createState() => MapSampleState();
}

class MapSampleState extends State<MapSample> {
  bool _desirePadding = true;
  late GoogleMapController _mapController;

  @override
  Widget build(BuildContext context) {
    LatLng myCoordinate = const LatLng(37.7749, -122.4194); // Center coordinate
    double desiredTopPadding = 50.0; // Desired top padding value in pixels
    double desiredBottomPadding =
        200.0; // Desired bottom padding value in pixels

    // Calculate the my lower coordinate
    double topPaddingInDegrees = (desiredTopPadding /
        (156543.03392 * cos(myCoordinate.latitude * pi / 180.0)));
    double bottomPaddingInDegrees = (desiredBottomPadding /
        (156543.03392 * cos(myCoordinate.latitude * pi / 180.0)));

    double myLowerCoordinateLatitude =
        myCoordinate.latitude - (bottomPaddingInDegrees - topPaddingInDegrees);

    debugPrint("MY LOWER COORDINATE $myLowerCoordinateLatitude");

    return Scaffold(
      body: GoogleMap(
        initialCameraPosition: CameraPosition(
          target: myCoordinate,
          zoom: 17.0,
        ),
        padding: _desirePadding == true
            ? EdgeInsets.only(
                top: desiredTopPadding, bottom: desiredBottomPadding)
            : const EdgeInsets.only(top: 0, bottom: 0),
        onMapCreated: (GoogleMapController controller) async {
          _mapController = controller;
          await Future.delayed(const Duration(milliseconds: 1000));
          _mapController
              .animateCamera(CameraUpdate.newCameraPosition(CameraPosition(
            target: myCoordinate,
            zoom: 17.0,
          )));
        },
        markers: {
          Marker(
            infoWindow: const InfoWindow(title: "My Coordinate"),
            markerId: const MarkerId('myMaker'),
            position: myCoordinate,
          ),
          Marker(
            infoWindow: const InfoWindow(title: "My Lower Coordinate"),
            markerId: const MarkerId('lowerMarker'),
            position: LatLng(myLowerCoordinateLatitude, myCoordinate.longitude),
          ),
        },
      ),
      floatingActionButton: Wrap(
        direction: Axis.vertical,
        children: <Widget>[
          Container(
            margin: const EdgeInsets.all(10),
            child: FloatingActionButton.extended(
              onPressed: () async {
                final c = CameraPosition(
                    target: _desirePadding
                        ? myCoordinate
                        : LatLng(
                            myLowerCoordinateLatitude, myCoordinate.longitude),
                    zoom: 17.0);

                _mapController.animateCamera(CameraUpdate.newCameraPosition(c));
              },
              label: _desirePadding
                  ? const Text('To My Coordinate')
                  : const Text('To My Lower Coordinate'),
              icon: const Icon(Icons.directions_boat),
            ),
          ),
          Container(
              margin: const EdgeInsets.all(10),
              child: FloatingActionButton.extended(
                onPressed: () {
                  setState(() {
                    _desirePadding = !_desirePadding;
                  });
                },
                backgroundColor: Colors.deepPurpleAccent,
                label: _desirePadding
                    ? const Text('Set Padding To Bottom: 0, Top: 0')
                    : Text(
                        'Set Padding To Bottom: $desiredBottomPadding, Top: $desiredTopPadding'),
                icon: const Icon(Icons.add),
              )),

          // Add more buttons here
        ],
      ),
    );
  }
}

精准获取中心坐标的方法

原方法依赖固定地球周长系数计算偏移,未考虑地图缩放层级、设备屏幕像素密度以及实时投影变化,导致精度不足。推荐以下两种精准方案:

方案一:直接获取当前相机目标坐标

当地图设置padding并完成相机移动后,通过GoogleMapController的getCameraPosition()方法直接获取当前相机中心坐标,这是最可靠的方式:

// 在需要获取坐标的时机调用(比如相机动画完成后)
CameraPosition currentCamera = await _mapController.getCameraPosition();
LatLng paddedCenter = currentCamera.target;
debugPrint("设置内边距后的中心坐标: $paddedCenter");

方案二:通过地图投影计算可视区域中心

利用地图投影将屏幕可视区域的中心像素坐标转换为经纬度,步骤如下:

  1. 获取地图组件的实际尺寸
  2. 计算padding后的有效可视区域中心像素点
  3. 通过Projection将像素点转为经纬度

示例代码:

// 确保地图渲染完成后执行
await Future.delayed(const Duration(milliseconds: 500));
final Projection projection = await _mapController.getProjection();
final Size mapSize = MediaQuery.of(context).size;

// 计算有效可视区域的高度
double visibleHeight = mapSize.height - desiredTopPadding - desiredBottomPadding;
// 可视区域中心的像素坐标(相对于地图组件左上角)
Offset centerPixel = Offset(
  mapSize.width / 2,
  desiredTopPadding + visibleHeight / 2,
);

// 转换为经纬度
LatLng paddedCenter = projection.fromScreenLocation(centerPixel);
debugPrint("计算得到的中心坐标: $paddedCenter");

优化原代码示例

将原代码的onMapCreated方法修改为如下,即可获取精准坐标:

onMapCreated: (GoogleMapController controller) async {
  _mapController = controller;
  await Future.delayed(const Duration(milliseconds: 1000));
  await _mapController.animateCamera(CameraUpdate.newCameraPosition(CameraPosition(
    target: myCoordinate,
    zoom: 17.0,
  )));
  // 获取设置padding后的真实中心坐标
  CameraPosition currentCamera = await _mapController.getCameraPosition();
  debugPrint("实际中心坐标: ${currentCamera.target}");
},

内容的提问来源于stack exchange,提问作者Cemang Anas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 19:50:28