在 Android 中旋转 MapView

Posted

技术标签:

【中文标题】在 Android 中旋转 MapView【英文标题】:Rotate MapView in Android 【发布时间】:2010-12-22 06:30:02 【问题描述】:

我正在编写一个 android 应用程序,其中一个功能是地图将根据指南针旋转(即,如果手机指向东方,则地图将被定向,以便地图的东侧位于顶部) .我发现以前的答案建议在 mapView 中编写 onDraw() 方法,但是,api 将方法更改为 final,因此它不能被覆盖。结果,我尝试像这样覆盖dispatchDraw() 方法:

注意:

-compass 是一个布尔值,如果为真,则旋转视图

-bearing 是一个浮点变量,具有视图应旋转的度数

protected void dispatchDraw(Canvas canvas) 
    canvas.save();
         if (compass) 
             final float w = this.getWidth();
             final float h = this.getHeight();

             final float scaleFactor = (float)(Math.sqrt(h * h + w * w) / Math.min(w, h));

             final float centerX = w / 2.0f;
             final float centerY = h / 2.0f;

             canvas.rotate(bearing, centerX, centerY);
             canvas.scale(scaleFactor, scaleFactor, centerX, centerY);

         
         super.dispatchDraw(canvas);
         canvas.restore();

【问题讨论】:

为什么需要重写 onDraw,难道不能只为 Activity 中的视图设置动画吗? @Matthew:你有答案吗,如果有,请给我解决方案 【参考方案1】:

感谢 pheelick 和 Nikita Koksharov 的回答,我设法根据指南针打开/关闭地图视图的旋转。

首先,您需要 MapViewCompassDemo.java两个内部 类,该类位于:Android_SDK_ Tools\add-ons\addon-google_apis-google-#\samples\MapsDemo \src\com\example\android\apis\view\

RotateView
SmoothCanvas

提取内部类RotateView到RotateView.java添加 SmoothCanvas作为RotateView.java的内部类而不是MapViewCompassDemo.java

public class RotateView extends ViewGroup implements SensorListener 
...
   static final class SmoothCanvas extends Canvas 
...
   //end SmoothCanvas 
//end RotateView 

maplayout.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/map_layout_container"
android:layout_
android:layout_
android:orientation="vertical" >

<LinearLayout
    android:id="@+id/rotating_view"
    android:layout_
    android:layout_ >

    <com.google.android.maps.MapView
        android:id="@+id/map_view"
        android:layout_
        android:layout_
        android:apiKey="##### YOUR MAP KEY HERE ######"
        android:clickable="true" />
</LinearLayout>

<ToggleButton
    android:id="@+id/button_compass"
    android:layout_
    android:layout_
    android:layout_alignParentBottom="true"
    android:layout_centerHorizontal="true"
    android:onClick="onClick"
    android:textOff="compass off"
    android:textOn="compass on" />

</RelativeLayout>

地图活动

 /**
 * Example activity on how to display a google map view rotation with compass
 * To make it work you need to add:
 *  - <uses-library android:name="com.google.android.maps" /> in the manifest.xml file
 *  - Your Android Maps API Key from https://developers.google.com/android/maps-api- signup
 *  - Set the project build target to "Google APIs"
 *  - Extract/Add the two inner classes RotateView and SmoothCanvas of MapViewCompassDemo.java found at: 
 * ..\Android\Android SDK Tools\add-ons\addon-google_apis-google-#\samples\MapsDemo\src\com\example\android\apis\view\
 * 
 * @author hsigmond - touchboarder.com - 
 *
 */
public class MapViewRotationWithCompass extends MapActivity 

private MapView mMapView;
private MyLocationOverlay mMyLocationOverlay = null;
private boolean mModeCompass = false;
private SensorManager mSensorManager;
private LinearLayout mRotateViewContainer;
private RotateView mRotateView;


@Override
public void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);

    setContentView(R.layout.maplayout);
    mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
    mRotateViewContainer = (LinearLayout) findViewById(R.id.rotating_view);
    mRotateView = new RotateView(this);

    // Sign Up for the Android Maps API at:
    // https://developers.google.com/android/maps-api-signup
    // Add the Android Maps API key to the MapView in the maplayout.xml file 
    mMapView = (MapView) findViewById(R.id.map_view);
    mMyLocationOverlay = new MyLocationOverlay(this, mMapView);     



@SuppressWarnings("deprecation")
public void onClick(View v) 

    switch (v.getId()) 

    case R.id.button_compass:
        if (mMyLocationOverlay.isCompassEnabled()) 
            mSensorManager.unregisterListener(mRotateView);
            mRotateView.removeAllViews();
            mRotateViewContainer.removeAllViews();
            mRotateViewContainer.addView(mMapView);
            mMyLocationOverlay.disableCompass();
            mModeCompass = false;
         else 
            mRotateViewContainer.removeAllViews();
            mRotateView.removeAllViews();
            mRotateView.addView(mMapView);
            mRotateViewContainer.addView(mRotateView);
            mMapView.setClickable(true);
            mSensorManager.registerListener(mRotateView,
                    SensorManager.SENSOR_ORIENTATION,
                    SensorManager.SENSOR_DELAY_UI);
            mMyLocationOverlay.enableCompass();
            mModeCompass = true;
        
        break;
    


@SuppressWarnings("deprecation")
@Override
public void onResume() 
    super.onResume();
    if (mModeCompass) 
        mMyLocationOverlay.enableCompass();
        mSensorManager.registerListener(mRotateView,
                SensorManager.SENSOR_ORIENTATION,
                SensorManager.SENSOR_DELAY_UI);
    


@Override
public void onPause() 
    super.onPause();
    mMyLocationOverlay.disableCompass();


@SuppressWarnings("deprecation")
@Override
protected void onStop() 
    mSensorManager.unregisterListener(mRotateView);
    super.onStop();


@Override
protected boolean isRouteDisplayed() 
    return (false);// Don't display a route



更新: 使用 Compass 示例项目旋转 Google MapView:https://www.dropbox.com/sh/c1encbc2lr63qd9/6C1C4hsrlT

【讨论】:

@Nirav Ranpara - 我已经用一个工作示例项目更新了答案。 这是显示当前位置的地图,但不幸的是地图不是用两根手指旋转的。 是的。但我想旋转地图【参考方案2】:

来自文档:

受保护的 void dispatchDraw(Canvas 画布)

由 draw 调用以绘制子视图。这可能会被派生类覆盖,以便在绘制其子级之前(但在绘制其自己的视图之后)获得控制。

所以覆盖 dispatchDraw 是不好的,因为主地图视图已经被绘制了

一种解决方案可能是将 MapView 添加为另一个 CustomView(ViewGroup 的子类)的子项,然后使用 CustomView 的 dispatchDraw 方法来绘制旋转的 MapView(现在是子类)。所以在 xml 你会做这样的事情:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_
  android:layout_ >

  <com.example.CustomView
    android:layout_
    android:layout_>

    <com.google.android.maps.MapView
      android:id="@+id/mapview"
      android:layout_
      android:layout_
      android:apiKey="XXXXXXXXXXXXXXXXX"/>

  </com.example.CustomView>
</RelativeLayout>

【讨论】:

【参考方案3】:

应该是这样的:

@Override
protected void dispatchDraw(Canvas canvas) 
    canvas.save(Canvas.MATRIX_SAVE_FLAG);
    if (compass) 
        // rotate the canvas with the pivot on the center of the screen
        canvas.rotate(-azimuth, getWidth() * 0.5f, getHeight() * 0.5f);
        super.dispatchDraw(canvas);
        canvas.restore();
    

【讨论】:

【参考方案4】:

查看ANDROID_SDK\add-ons\addon-google_apis-google_inc_-7\samples\MapsDemo 中的 MapsDemo 示例。它有旋转地图演示。

【讨论】:

【参考方案5】:

此答案适用于Google Maps api v2。 可以通过向 Sensor Listener for Orientation 注册您的应用程序并获得 在onSensorChanged 内相对于真北的角度并相应地更新相机。 角钢可用于承重。可以使用以下代码:

尝试使用 getOrinetation api,而不是使用 Sensor.TYPE_ORIENTATIONSensor.TYPE_ORIENTATION 已弃用。

@Override
protected void onResume() 
    // TODO Auto-generated method stub
    super.onResume();
    if (sensorManager != null)
        sensorManager.registerListener(this,
                sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION),
                SensorManager.SENSOR_DELAY_GAME);


public void onSensorChanged(SensorEvent event) 

    float degree = Math.round(event.values[0]);

    Log.d(TAG, "Degree ---------- " + degree);

    updateCamera(degree);



private void updateCamera(float bearing) 
    CameraPosition oldPos = googleMap.getCameraPosition();

    CameraPosition pos = CameraPosition.builder(oldPos).bearing(bearing)
            .build();

    googleMap.moveCamera(CameraUpdateFactory.newCameraPosition(pos));


【讨论】:

有什么办法可以改变旋转轴吗?

以上是关于在 Android 中旋转 MapView的主要内容,如果未能解决你的问题,请参考以下文章

Android:在 Recyclerview 中更改图像旋转

在 Android 中旋转 MapView

如何在android中旋转按钮的文本?

在android中自动旋转全屏视频

在android中旋转控件

关于android中调用系统拍照,返回图片是旋转90度