在最大缩放级别平移MapView时GeoPoint和/或android.maps.Projection的奇怪行为

时间:2011-03-22 00:37:38

标签: android

我遇到了一个奇怪的问题,点使用谷歌地图套件获得抵消。

我有一个显示路线的MapView。我注意到,如果我一直放大,然后平移,我的路线就会被修剪到窗口边缘附近。经过对我自己的代码的大量调试后,我发现即使是这样一个简单的案例也足以重现这个问题:

            GeoPoint midPoint = projection.fromPixels(mapView.getWidth()/2, mapView.getHeight()/2);
            GeoPoint nextPoint = new GeoPoint(midPoint.getLatitudeE6(), midPoint.getLongitudeE6());
            pathPaint.setColor(0xFF00FF00);
            projection.toPixels(midPoint, screenPoint);
            canvas.drawCircle(screenPoint.x, screenPoint.y, 5, pathPaint);
            pathPaint.setColor(0xFF0000FF);
            projection.toPixels(nextPoint, screenPoint);
            canvas.drawCircle(screenPoint.x, screenPoint.y, 5, pathPaint);

这使用MapView.getProjection()返回的Projection类将像素坐标转换为GeoPoint。然后使用相同的纬度/经度创建第二个GeoPoint。最后,它将这两个GeoPoints转换回屏幕坐标,并在此位置绘制两个圆圈,一个在另一个上面。

除非你平移,否则第二个圆圈会偏离第一个圆圈。它们具有相同的纬度/经度坐标(我在绘图后检查),但最终会转换为不同的屏幕坐标。我的调试主要集中在横向平移,但我相信垂直平移可能会遇到类似的问题,基于我在原始应用程序代码中看到的内容。

据我所知,map包创建的任何点都可以正常工作,但通过调用new GeoPoint(lat,lon)创建的任何点都会出现这种情况。

我创建了一个简单的精简应用程序,它展示了这种行为,粘贴在下面。 (地图图块不会下载,因为我没有费心去签名,但你不需要它们来查看问题。)只需启动它,一直放大,然后开始向左或向右平移。观察绿色和蓝色点的分歧,并见证Log.d打印,表明它们仍然具有相同的纬度/经度。

(是否有更好/首选的方式发布示例项目?对不起,这是我在这里发布的第一篇文章。)

的src /示例/ MYSAMPLE / MapOverlay.java:

package example.mysample;

import java.util.ArrayList;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.RadialGradient;
import android.graphics.Shader;
import android.view.MotionEvent;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;
import com.google.android.maps.Projection;

import android.util.Log;

class MapOverlay extends Overlay
{
    public MapOverlay(MapScreen activity)
    {
        super();

        paint = new Paint();
        paint.setStyle(Paint.Style.FILL_AND_STROKE);
        paint.setAntiAlias(true);
    }

    @Override public boolean onTouchEvent(MotionEvent e, MapView mapView) {
        int motionAction = e.getAction();
        if ( motionAction == MotionEvent.ACTION_MOVE ) {
            dragging = true;
        }
        if ( motionAction == MotionEvent.ACTION_UP || motionAction == MotionEvent.ACTION_CANCEL ) {
            dragging = false;
        }
        return super.onTouchEvent(e, mapView);
    }

    @Override public void draw(Canvas canvas, MapView mapView, boolean shadow) {
        if (!shadow && !dragging) {
            Projection projection = mapView.getProjection();

            // Draw two circles at the center
            // One with a virgin point, one that we constructed with the same coordinates
            GeoPoint midPoint = projection.fromPixels(mapView.getWidth()/2, mapView.getHeight()/2);
            GeoPoint nextPoint = new GeoPoint(midPoint.getLatitudeE6(), midPoint.getLongitudeE6());
            paint.setColor(0xFF00FF00);
            projection.toPixels(midPoint, screenPoint);
            canvas.drawCircle(screenPoint.x, screenPoint.y, 5, paint);
            paint.setColor(0xFF0000FF);
            projection.toPixels(nextPoint, screenPoint);
            canvas.drawCircle(screenPoint.x, screenPoint.y, 5, paint);

            // These print EQUAL.
            Log.d("BKC DEBUG", "Midpoint and our own midpoint have " +
                ((midPoint.getLatitudeE6() == nextPoint.getLatitudeE6()) ? "EQUAL" : "UNEQUAL") +
                " latitudes, and " +
                ((midPoint.getLongitudeE6() == nextPoint.getLongitudeE6()) ? "EQUAL" : "UNEQUAL") +
                " longitudes");
        }
    }

    private Paint paint;
    private boolean dragging;
    private Point screenPoint = new Point();

}

的src /示例/ MYSAMPLE / MapScreen.java:

package example.mysample;

import android.os.Bundle;
import android.view.View;
import android.widget.Toast;
import android.util.Log;

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

public class MapScreen extends MapActivity
{

    @Override public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        setContentView(R.layout.map);

        mapView = (MapView)findViewById(R.id.map_map);
        mapView.setBuiltInZoomControls(true);
        mapView.getOverlays().add(new MapOverlay(this));

        MapController controller;
        controller = mapView.getController();
        controller.setZoom(17);
        controller.animateTo(new GeoPoint(36000000, -90000000));

    }

    @Override
    public boolean isRouteDisplayed() {
        return true;
    }

    private MapView mapView;

}

RES /布局/ map.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="#414141"
    >    

 <com.google.android.maps.MapView
            android:id="@+id/map_map"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:layout_marginLeft="3dip"
            android:layout_marginRight="3dip"
            android:layout_marginTop="3dip"
            android:layout_marginBottom="3dip"
            android:apiKey="0jPQdwUtQGBYfPALki6ghGG_X9Jpf-SllYckR4w"
            android:layout_centerInParent="true"
            android:clickable="true"
            />

</RelativeLayout>

的AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="example.mysample"
      android:versionCode="1"
      android:versionName="2.0.1">
    <uses-sdk android:minSdkVersion="4" />

    <!--uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /-->
    <!--uses-permission android:name="android.permission.READ_PHONE_STATE" /-->
    <uses-permission android:name="android.permission.INTERNET" />
    <!--uses-permission android:name="android.permission.WAKE_LOCK" /-->
    <!--uses-permission android:name="android.permission.READ_LOGS" /-->
    <!--uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /-->

    <!--application android:name="src.example.mysample.AppMain"
                 android:label="MySample"
                 android:icon="@drawable/icon_android"
                 android:theme="@android:style/Theme.NoTitleBar"
                 -->

    <application android:name="android.app.Application"
        android:label="MySample" >

        <uses-library android:name="com.google.android.maps"/>

        <!-- Main activity -->
        <activity android:name="example.mysample.MapScreen"
                  android:clearTaskOnLaunch="true"
                  android:label="MySample"
                  android:screenOrientation="portrait">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <!-- Other activities -->
        <!--activity android:name="example.mysample.SomethingElse"
                  android:label="Something"
                  android:screenOrientation="portrait"/-->

    </application>
</manifest>

build.xml(从模板不变):

<?xml version="1.0" encoding="UTF-8"?>
<project name="PROJECT_NAME" default="help">

<!-- The local.properties file is created and updated by the 'android'
     tool.
     It contains the path to the SDK. It should *NOT* be checked into
     Version Control Systems. -->
    <property file="local.properties" />

    <!-- The build.properties file can be created by you and is never touched
         by the 'android' tool. This is the place to change some of the
         default property values used by the Ant rules.
         Here are some properties you may want to change/update:

         source.dir
             The name of the source directory. Default is 'src'.
         out.dir
             The name of the output directory. Default is 'bin'.

         Properties related to the SDK location or the project target should
         be updated using the 'android' tool with the 'update' action.

         This file is an integral part of the build system for your
         application and should be checked into Version Control Systems.

         -->
    <property file="build.properties" />

    <!-- The default.properties file is created and updated by the 'android'
         tool, as well as ADT.
         This file is an integral part of the build system for your
         application and should be checked into Version Control Systems. -->
    <property file="default.properties" />

    <!-- Custom Android task to deal with the project target, and import the
         proper rules.
         This requires ant 1.6.0 or above. -->
    <path id="android.antlibs">
        <pathelement path="${sdk.dir}/tools/lib/anttasks.jar" />
        <pathelement path="${sdk.dir}/tools/lib/sdklib.jar" />
        <pathelement path="${sdk.dir}/tools/lib/androidprefs.jar" />
    </path>

    <taskdef name="setup"
        classname="com.android.ant.SetupTask"
        classpathref="android.antlibs" />

<!-- extension targets. Uncomment the ones where you want to do custom work
     in between standard targets -->
<!--
    <target name="-pre-build">
    </target>
    <target name="-pre-compile">
    </target>

    [This is typically used for code obfuscation.
     Compiled code location: ${out.classes.absolute.dir}
     If this is not done in place, override ${out.dex.input.absolute.dir}]
    <target name="-post-compile">
    </target>
-->


    <!-- Execute the Android Setup task that will setup some properties
         specific to the target, and import the build rules files.

         The rules file is imported from
            <SDK>/platforms/<target_platform>/ant/ant_rules_r#.xml

         To customize existing targets, there are two options:
         - Customize only one target:
             - copy/paste the target into this file, *before* the
               <setup> task.
             - customize it to your needs.
         - Customize the whole script.
             - copy/paste the content of the rules files (minus the top node)
               into this file, *after* the <setup> task
             - disable the import of the rules by changing the setup task
               below to <setup import="false" />.
             - customize to your needs.
    -->
    <setup />

</project>

1 个答案:

答案 0 :(得分:1)

我也面临这个问题 - 似乎是Android Mapview API中的一个错误 - 我认为Star的问题是这样的: http://code.google.com/p/android/issues/detail?id=17387&can=5&colspec=ID%20Type%20Status%20Owner%20Summary%20Stars 还有一个可能的解决方法是丑陋的,但适用于评论 - 基本上你确定错误并相应地调整结果