抵减MapFragment的中心的动画移动两个所述目标的纬度/经度和缩放水平经度、纬度、缩放、所述

2023-09-03 21:41:30 作者:你是我最后的答案

我有一个与覆盖在它上面的透明视图中MapFragment的UI。地图占据了整个屏幕,而显示在屏幕的只是左边第三位。其结果,在地图上的默认的中心是关闭的。当有人点击一个标记,我想中心的标记在MapFragment。

I've got a UI that has a MapFragment with a transparent View overlaid on top of it. The map takes up the entire screen, whereas the View is just the left third of the screen. As a result, the default "center" of the map is off. When someone clicks on a marker, I want to center that marker in the wholly visible area of the MapFragment (not the center of the MapFragment itself).

由于这是很难描述文字,让我用了几张照片。假设这就是我的UI外观:

Since this is hard to describe with words, let me use a few pictures. Suppose this is how my UI looks:

当用户点击一个标记,我想这两个中心,它的和的放大到接近看到它。没有任何调整,这是你会得到什么:

When the user clicks a marker, I want to both center it and zoom in to see it closer. Without any adjustments, this is what you'll get:

我要的是对标记为中心,但在太空的权利,这样的:

What I want is for the marker to be centered, but in the space to the right, like this:

这是很容易实现这一壮举的,如果你不使用的地图投影更改缩放级别:

It's very easy to achieve this feat if you're not changing the zoom level using the map's projection:

// Offset the target latitude/longitude by preset x/y ints
LatLng target = new LatLng(latitude, longitude);
Projection projection = getMap().getProjection();
Point screenLocation = projection.toScreenLocation(target);
screenLocation.x += offsetX;
screenLocation.y += offsetY;
LatLng offsetTarget = projection.fromScreenLocation(screenLocation);

// Animate to the calculated lat/lng
getMap().animateCamera(CameraUpdateFactory.newLatLng(offsetTarget));

不过,如果你正在改变缩放级别的同时,以上计算不工作(因为纬度/经度偏移的变化在不同的缩放级别)。

However, if you're changing the zoom level at the same time, the above calculations don't work (since the lat/lng offsets change at different zoom levels).

让我跑下来试图修复列表:

Let me run down a list of attempted fixes:

更​​改缩放级别快,做计算,缩放回原来的摄像头位置,然后动画。不幸的是,相机突然改变(哪怕只是一秒钟)家饭店目前很明显的,我想,以避免闪烁。

Changing the zoom level quickly, doing the calculations, zooming back to the original camera position, then animating. Unfortunately the sudden camera change (even if it's only for a split second) is unfortunately very obvious and I'd like to avoid the flicker.

叠加在彼此的顶部的两个MapFragments,具有一个执行计算,而其他显示器。我发现MapFragments并没有真正建立在彼此的顶部进行分层(也有不可避免的缺陷沿着这条路)。

Overlaying two MapFragments on top of each other, having one do the calculations while the other displays. I've found that MapFragments are not really built to be layered on top of each other (there are unavoidable bugs down this route).

按平方变焦水平的差异修改屏幕位置的X / Y。理论上这应该工作,但它由相当多的(〜.1经/纬度,这也足以成为路要走)总是关闭。

Modifying the screen location's x/y by the difference in zoom level squared. Theoretically this should work but it's always off by quite a bit (~.1 latitude/longitude, which is enough to be way off).

有没有一种方法来计算offsetTarget甚至与缩放级别变化?

Is there a way to calculate the offsetTarget even with the zoom level changing?

推荐答案

编辑:低于code是pcated V1地图去$ P $。该SO回答国家如何在V2执行类似的操作:How得到纬度/经度跨度在谷歌地图V2为Android

The below code is for the deprecated v1 maps. This SO answer states how to perform similar actions in v2: How to get Latitude/Longitude span in Google Map V2 for Android

您需要应该在经度/纬度和百分比,而不是像素的关键方法。眼下,图形页面会缩小围绕地图的中心,然后移动到recenter曝光区域的脚。你可以得到的宽度的放大程度,因素一些屏幕偏后,再重定位地图。下面是低于code在行动样品截图$ P $后pssing的+:前 在 主要code:

The key methods you need should work in long/lat and percentages instead of pixels. Right now, the mapview will zoom around the center of the map, and then move to 'recenter' the pin in the exposed area. You can get the width after the zoom in degrees, factor in some screen bias, and then recenter the map. Here is a sample screenshot of the below code in action after pressing the '+': before after Main code:

@Override
            public void onZoom(boolean zoomIn) {
                // TODO Auto-generated method stub
                controller.setZoom(zoomIn ? map.getZoomLevel()+1 : map.getZoomLevel()-1);
                int bias = (int) (map.getLatitudeSpan()* 1.0/3.0); // a fraction of your choosing
                map.getLongitudeSpan();
                controller.animateTo(new GeoPoint(yourLocation.getLatitudeE6(),yourLocation.getLongitudeE6()-bias));

            }

所有code:

All code:

    package com.example.testmapview;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.ItemizedOverlay;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;

import android.os.Bundle;
import android.app.Activity;
import android.graphics.drawable.Drawable;
import android.view.Menu;
import android.widget.ZoomButtonsController;
import android.widget.ZoomButtonsController.OnZoomListener;

public class MainActivity extends MapActivity {
    MapView map;
    GeoPoint yourLocation;
    MapController controller;
    ZoomButtonsController zoomButtons;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        map=(MapView)findViewById(R.id.mapview);
        map.setBuiltInZoomControls(true);
        controller = map.getController();
        zoomButtons = map.getZoomButtonsController();

        zoomButtons.setOnZoomListener(new OnZoomListener(){

            @Override
            public void onVisibilityChanged(boolean arg0) {
                // TODO Auto-generated method stub

            }

            @Override
            public void onZoom(boolean zoomIn) {
                // TODO Auto-generated method stub
                controller.setZoom(zoomIn ? map.getZoomLevel()+1 : map.getZoomLevel()-1);
                int bias = (int) (map.getLatitudeSpan()* 1.0/3.0); // a fraction of your choosing
                map.getLongitudeSpan();
                controller.animateTo(new GeoPoint(yourLocation.getLatitudeE6(),yourLocation.getLongitudeE6()-bias));

            }
        });

        //Dropping a pin, setting center
        Drawable marker=getResources().getDrawable(android.R.drawable.star_big_on);
        MyItemizedOverlay myItemizedOverlay = new MyItemizedOverlay(marker);
        map.getOverlays().add(myItemizedOverlay);
        yourLocation = new GeoPoint(0, 0);
        controller.setCenter(yourLocation);
        myItemizedOverlay.addItem(yourLocation, "myPoint1", "myPoint1");
        controller.setZoom(5);

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }

    @Override
    protected boolean isRouteDisplayed() {
        // TODO Auto-generated method stub
        return false;
    }

}

和一个基本的布局:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.testmapview"
    android:versionCode="1"
    android:versionName="1.0" >
<meta-data
    android:name="com.google.android.maps.v2.API_KEY"
    android:value="YOURKEYHERE:)"/>
    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="16" />

<uses-permission android:name="android.permission.INTERNET" /> 
    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <uses-library android:name="com.google.android.maps"/>

        <activity
            android:name="com.example.testmapview.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

如果这并不能完全解答您的问题,请让我知道,因为这是一个有趣的实验来玩弄。

If this doesn't fully answer your question, please let me know as this was a fun experiment to play around with.