3.0+百度地图,如何获取地图中心点位置(每次滑动地图后都能够获取地图的中心点位置,并做出相应的操作)...

本文介绍了一种基于百度地图API的应用场景实现方案,包括地图定位、滑动后重新搜索附近地点的功能实现,以及如何避免常见错误。

现在有这样一个业务:

1.将地图定位到指定的经纬度位置,当地图停止滑动时搜索附近的地址信息列表,并显示再ListView中。

2.每次滑动地图都需要根据地图中心点位置搜索附近1000米范围内的地址,并显示再列表,直至退出。

 

下面是具体实现的代码:

一:实例化PoiSearch并设置获取结果的监听器setOnGetPoiSearchResultListener

// 创建POI检索实例
        poiSearch = PoiSearch.newInstance();
        // 设置监听器
        poiSearch.setOnGetPoiSearchResultListener(poiSearchListener);
        baiduMap = mapView.getMap();
        //设置地图中心点位置
        MapStatus status = new MapStatus.Builder().target(new LatLng(MyLocation.getInstance().getLocation().getLatitude(), MyLocation.getInstance().getLocation().getLongitude())).build();
        searchMoveFinish(status);
        // 设置地图的缩放级别
        MapStatus mapStatus = new MapStatus.Builder().zoom(18).build();
        baiduMap.setMapStatus(MapStatusUpdateFactory.newMapStatus(mapStatus));

二、获取poi搜索结果监听器:次监听的目的是可以使用户手动模糊搜索

/**
     * 创建POI检索监听者
     */
    OnGetPoiSearchResultListener poiSearchListener = new OnGetPoiSearchResultListener() {

        @Override
        public void onGetPoiResult(PoiResult poiResult) {
            if (poiResult != null && poiResult.getAllPoi() != null) {
                adapter.setData(poiResult.getAllPoi());
                mSearchResultList.setAdapter(adapter);
                adapter.notifyDataSetChanged();
            } else {
                ToastUtil.getInstance().showTips(ChooseLocationActivity.this,
                        ToastUtil.TOAST_WARING, "没有更多了!");
            }
            adapter.setSelected(-1);
        }

        @Override
        public void onGetPoiDetailResult(PoiDetailResult poiDetailResult) {
            // 获取Place详情页检索结果
            ToastUtil.getInstance().showTips(ChooseLocationActivity.this,
                    ToastUtil.TOAST_WARING, "特美的,居然在这里执行了!");
        }
    };

三、监听地图的状态变化

baiduMap.setOnMapStatusChangeListener(new OnMapStatusChangeListener() {

            @Override
            public void onMapStatusChangeStart(MapStatus status) {

            }

            // 移动结束,在这里需要计算出中心点坐标
            @Override
            public void onMapStatusChangeFinish(MapStatus status) {
                searchMoveFinish(status);

            }

            @Override
            public void onMapStatusChange(MapStatus status) {

            }
        });

第四、(重要)根据地理位置信息搜索指定经纬度1000米范围内的所有的地址信息,此方法是“每次滑动地图后都能够获取地图的中心点位置,并做出相应的操作”的主要方法

private void searchMoveFinish(MapStatus status) {
        GeoCoder geoCoder = GeoCoder.newInstance();
        ReverseGeoCodeOption reverCoder = new ReverseGeoCodeOption();
        reverCoder.location(status.target);
        geoCoder.reverseGeoCode(reverCoder); //
        geoCoder.setOnGetGeoCodeResultListener(new OnGetGeoCoderResultListener() {

            @Override
            public void onGetReverseGeoCodeResult(ReverseGeoCodeResult arg0) { // TODO
                                                                                // stub
                if (arg0 != null && arg0.getPoiList() != null) {
                    adapter.setData(arg0.getPoiList());
                    mSearchResultList.setAdapter(adapter);
                    adapter.notifyDataSetChanged();
                } else {
                    ToastUtil.getInstance().showTips(
                            ChooseLocationActivity.this,
                            ToastUtil.TOAST_WARING, "没有更多了!");
                }
            }

            @Override
            public void onGetGeoCodeResult(GeoCodeResult arg0) { //

            }
        });

    }

测试过程遇到的一些问题:注意,移动地图后根据,地图中心点进行搜索时,一定不要使用下面这段代码进行处理:

PoiNearbySearchOption option = new PoiNearbySearchOption();
        option.location(new LatLng(MyLocation.getInstance().getLocation()
                .getLatitude(), MyLocation.getInstance().getLocation()
                .getLongitude()));
        option.keyword(keyword);
        option.radius(1000);
        option.pageNum(10);
        poiSearch.searchNearby(option);

因为测试过程中发现,如果使用了上述代码进行中心点范围内搜索,则每次 执行过后中心点的经纬度坐标是不会发生相应变化的。应该使用:“第四”部中的方法进行搜索,这样搜索出的结果就是我们所预期的结果

 

转载于:https://www.cnblogs.com/tony-yang-flutter/p/4434452.html

<think>我们将在Unity中实现地图的拖拽和缩放功能,这通常用于策略游戏或地图浏览界面。以下是具体实现步骤:1.**拖拽功能**:通过鼠标点击拖动来移动地图。2.**缩放功能**:通过鼠标滚轮或触摸手势来缩放地图。我们将使用Unity的UGUI系统,利用`RectTransform`和`Canvas`组件。假设地图元素都放在一个`Canvas`下,我们将通过控制这个Canvas的子物体(地图容器)的`RectTransform`来实现拖拽和缩放。具体实现:-**拖拽**:当用户按下鼠标时记录当前位置,然后在拖动时计算偏移量移动地图容器。-**缩放**:监听鼠标滚轮事件,调整地图容器的缩放比例,限制在最小和最大缩放值之间。代码实现如下:</think>### Unity地图拖拽与缩放功能实现 以下是完整的拖拽和缩放功能实现方案,包含平滑动画、边界限制和性能优化: #### 1. 基础拖拽与缩放控制器 ```csharp using UnityEngine; using UnityEngine.EventSystems; public class MapDragZoom : MonoBehaviour, IDragHandler, IPointerDownHandler, IScrollHandler { [Header("拖拽设置")] public bool allowDrag = true; public float dragSensitivity = 1f; [Header("缩放设置")] public bool allowZoom = true; public float zoomSpeed = 0.1f; public float minZoom = 0.5f; public float maxZoom = 3f; public float zoomLerpSpeed = 5f; [Header("边界限制")] public bool clampPosition = true; public Vector2 minPosition = new Vector2(-500, -300); public Vector2 maxPosition = new Vector2(500, 300); private RectTransform rectTransform; private Vector2 lastMousePosition; private float targetZoom = 1f; private Vector3 originalPosition; private Vector3 originalScale; void Start() { rectTransform = GetComponent<RectTransform>(); originalPosition = rectTransform.localPosition; originalScale = rectTransform.localScale; targetZoom = rectTransform.localScale.x; } void Update() { // 平滑缩放动画 if (Mathf.Abs(rectTransform.localScale.x - targetZoom) > 0.01f) { float newScale = Mathf.Lerp( rectTransform.localScale.x, targetZoom, Time.deltaTime * zoomLerpSpeed ); rectTransform.localScale = Vector3.one * newScale; // 缩放时保持鼠标位置为中心 if (allowZoom && Input.mouseScrollDelta != Vector2.zero) { Vector2 localPoint; RectTransformUtility.ScreenPointToLocalPointInRectangle( rectTransform.parent as RectTransform, Input.mousePosition, null, out localPoint ); Vector2 offset = localPoint * (newScale - rectTransform.localScale.x); rectTransform.localPosition -= (Vector3)offset; } } // 位置边界限制 if (clampPosition) { Vector3 clampedPosition = rectTransform.localPosition; clampedPosition.x = Mathf.Clamp(clampedPosition.x, minPosition.x, maxPosition.x); clampedPosition.y = Mathf.Clamp(clampedPosition.y, minPosition.y, maxPosition.y); rectTransform.localPosition = clampedPosition; } } public void OnPointerDown(PointerEventData eventData) { lastMousePosition = Input.mousePosition; } public void OnDrag(PointerEventData eventData) { if (!allowDrag) return; Vector2 currentMousePosition = Input.mousePosition; Vector2 diff = currentMousePosition - lastMousePosition; // 根据当前缩放比例调整拖动灵敏度 float sensitivity = dragSensitivity / rectTransform.localScale.x; rectTransform.localPosition += (Vector3)(diff * sensitivity); lastMousePosition = currentMousePosition; } public void OnScroll(PointerEventData eventData) { if (!allowZoom) return; float scroll = Input.mouseScrollDelta.y; if (scroll != 0) { // 计算新的缩放值 float zoomDelta = scroll * zoomSpeed; targetZoom = Mathf.Clamp(targetZoom + zoomDelta, minZoom, maxZoom); } } // 重置地图位置和缩放 public void ResetView() { rectTransform.localPosition = originalPosition; rectTransform.localScale = originalScale; targetZoom = originalScale.x; } } ``` #### 2. 高级功能:双击聚焦节点 ```csharp using UnityEngine; using UnityEngine.EventSystems; public class NodeFocus : MonoBehaviour, IPointerClickHandler { public MapDragZoom mapDragZoom; public float focusDuration = 0.8f; public float focusZoom = 1.5f; public void OnPointerClick(PointerEventData eventData) { // 双击事件 if (eventData.clickCount == 2) { RectTransform nodeRect = GetComponent<RectTransform>(); RectTransform mapRect = mapDragZoom.GetComponent<RectTransform>(); // 计算节点在父容器中的位置 Vector2 nodePosition = nodeRect.anchoredPosition; Vector2 mapPosition = mapRect.anchoredPosition; // 计算需要移动的偏移量 Vector2 viewportCenter = Vector2.zero; // 假设视口中心是(0,0) Vector2 targetPosition = viewportCenter - nodePosition; // 启动聚焦动画 StartCoroutine(FocusOnNode(targetPosition)); } } private System.Collections.IEnumerator FocusOnNode(Vector2 targetPosition) { Vector3 startPos = mapDragZoom.transform.localPosition; Vector3 endPos = new Vector3(targetPosition.x, targetPosition.y, startPos.z); float startZoom = mapDragZoom.targetZoom; float endZoom = focusZoom; float elapsed = 0f; while (elapsed < focusDuration) { elapsed += Time.deltaTime; float t = Mathf.SmoothStep(0, 1, elapsed / focusDuration); mapDragZoom.transform.localPosition = Vector3.Lerp(startPos, endPos, t); mapDragZoom.targetZoom = Mathf.Lerp(startZoom, endZoom, t); yield return null; } mapDragZoom.transform.localPosition = endPos; mapDragZoom.targetZoom = endZoom; } } ``` #### 3. 性能优化:基于视口的渲染 ```csharp using UnityEngine; public class ViewportOptimization : MonoBehaviour { public RectTransform viewportRect; public MapRenderer mapRenderer; void LateUpdate() { // 获取视口在父容器中的位置 Rect viewport = GetViewportRect(); // 更新所有节点的可见性 foreach (Transform node in mapRenderer.mapContainer) { Rect nodeRect = GetNodeRect(node); node.gameObject.SetActive(viewport.Overlaps(nodeRect)); } } private Rect GetViewportRect() { Vector2 size = viewportRect.rect.size; Vector2 position = (Vector2)viewportRect.localPosition - size * 0.5f; return new Rect(position, size); } private Rect GetNodeRect(Transform node) { RectTransform rt = node.GetComponent<RectTransform>(); Vector2 size = rt.rect.size * rt.localScale.x; Vector2 position = (Vector2)rt.localPosition - size * 0.5f; return new Rect(position, size); } } ``` #### 4. 触摸屏手势支持 ```csharp using UnityEngine; using UnityEngine.EventSystems; public class TouchGestures : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler { private const float PinchThreshold = 0.1f; private MapDragZoom mapDragZoom; private Vector2 touchStartPosition; private float startDistance; private float startZoom; void Start() { mapDragZoom = GetComponent<MapDragZoom>(); } public void OnBeginDrag(PointerEventData eventData) { if (Input.touchCount == 1) { touchStartPosition = Input.GetTouch(0).position; } else if (Input.touchCount == 2) { // 记录初始触摸点距离 startDistance = Vector2.Distance( Input.GetTouch(0).position, Input.GetTouch(1).position ); startZoom = mapDragZoom.targetZoom; } } public void OnDrag(PointerEventData eventData) { if (Input.touchCount == 1) { // 单指拖拽 Vector2 currentPosition = Input.GetTouch(0).position; Vector2 diff = currentPosition - touchStartPosition; float sensitivity = mapDragZoom.dragSensitivity / mapDragZoom.targetZoom; transform.localPosition += (Vector3)(diff * sensitivity); touchStartPosition = currentPosition; } else if (Input.touchCount == 2) { // 双指缩放 float currentDistance = Vector2.Distance( Input.GetTouch(0).position, Input.GetTouch(1).position ); float pinchAmount = (currentDistance - startDistance) * 0.01f; mapDragZoom.targetZoom = Mathf.Clamp( startZoom + pinchAmount, mapDragZoom.minZoom, mapDragZoom.maxZoom ); } } public void OnEndDrag(PointerEventData eventData) { // 可选:添加惯性滑动效果 } } ``` #### 5. 使用示例(附加到地图容器) ```csharp // 在Unity编辑器中设置 // 1. 将MapDragZoom脚本添加到地图容器对象 // 2. 配置参数: // - Drag Sensitivity: 0.8 // - Zoom Speed: 0.15 // - Min Zoom: 0.3 // - Max Zoom: 3.0 // - Zoom Lerp Speed: 8 // - Clamp Position: true // - 设置合适的边界值 // 3. 为每个节点添加NodeFocus组件关联MapDragZoom // 4. 添加ViewportOptimization组件到视口对象 ``` ### 实现原理详解 1. **拖拽功能**: - 实现`IDragHandler`接口处理鼠标/触摸拖动事件 - 计算鼠标位置偏移量移动地图容器 - 根据当前缩放比例调整灵敏度(缩放越大,拖拽越快) - 使用`clampPosition`限制地图边界 2. **缩放功能**: - 实现`IScrollHandler`处理鼠标滚轮事件 - 使用Lerp平滑过渡缩放值 - 缩放时保持鼠标位置中心点 - 设置最小/最大缩放限制 3. **高级功能**: - **双击聚焦**:计算节点位置动画移动到视口中心 - **性能优化**:基于视口裁剪不可见节点 - **触摸手势**:支持单指拖拽和双指缩放 - **边界限制**:防止地图移出可视区域 4. **数学计算**: - 屏幕坐标到UI坐标转换:`RectTransformUtility.ScreenPointToLocalPointInRectangle` - 矩形重叠检测:`Rect.Overlaps` - 平滑动画:`Mathf.SmoothStep`和`Mathf.Lerp` ### 优化建议 1. **对象池优化**: ```csharp public class NodePool : MonoBehaviour { public GameObject nodePrefab; public int initialPoolSize = 50; private Queue<GameObject> pool = new Queue<GameObject>(); void Start() { for (int i = 0; i < initialPoolSize; i++) { GameObject node = Instantiate(nodePrefab, transform); node.SetActive(false); pool.Enqueue(node); } } public GameObject GetNode() { if (pool.Count > 0) { GameObject node = pool.Dequeue(); node.SetActive(true); return node; } return Instantiate(nodePrefab, transform); } public void ReturnNode(GameObject node) { node.SetActive(false); pool.Enqueue(node); } } ``` 2. **动态加载**: ```csharp IEnumerator LoadVisibleNodes() { Rect viewport = GetViewportRect(); foreach (MapNode node in allNodes) { if (viewport.Overlaps(node.rect)) { if (!node.isLoaded) { GameObject nodeObj = nodePool.GetNode(); // 初始化节点... yield return null; // 分帧加载 } } else if (node.isLoaded) { nodePool.ReturnNode(node.gameObject); } } } ``` 3. **LOD(细节层次)优化**: ```csharp void UpdateNodeDetail() { float zoomLevel = mapDragZoom.targetZoom; foreach (NodeVisual node in visibleNodes) { if (zoomLevel > 1.5f) { node.ShowDetails(); // 显示详细信息 } else if (zoomLevel > 0.8f) { node.ShowNormal(); // 普通显示 } else { node.ShowSimple(); // 简化显示 } } } ``` ### 使用注意事项 1. **UI层级设置**: - 确保地图容器在Scroll Rect组件下 - 设置Canvas的Render Mode为Screen Space - Camera或Overlay 2. **事件穿透问题**: - 添加`CanvasGroup`组件设置`Blocks Raycasts`属性 - 使用`EventSystem.current.IsPointerOverGameObject()`检测UI点击 3. **多分辨率适配**: ```csharp void UpdateBoundaries() { RectTransform parentRect = transform.parent.GetComponent<RectTransform>(); Vector2 parentSize = parentRect.rect.size; minPosition = -parentSize * 0.5f; maxPosition = parentSize * 0.5f; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值