在Android中旋转MapView

时间:2009-12-02 02:56:13

标签: android google-maps map rotation android-mapview

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

注意:

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

-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();
}

5 个答案:

答案 0 :(得分:8)

感谢pheelicks和Nikita Koksharov的回答,我设法根据指南针打开/关闭mapv​​iew的旋转。

首先,您需要找到的两个内部 MapViewCompassDemo.java :Android_SDK_ Tools \ add-ons \ addon-google_apis-google - #\ samples \ MapsDemo \ SRC \ COM \示例\机器人\的API \视图\

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_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >

<LinearLayout
    android:id="@+id/rotating_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

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

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

</RelativeLayout>

MapActivity

 /**
 * 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

答案 1 :(得分:3)

来自文档:

  

protected void dispatchDraw(Canvas canvas)

     

通过绘图调用以绘制子视图。这可以被派生类覆盖,以便在绘制子项之前获得控制(但是在绘制了它自己的视图之后)。

因此,覆盖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_width="fill_parent"
  android:layout_height="fill_parent" >

  <com.example.CustomView
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">

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

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

答案 2 :(得分:1)

它应该是这样的:

@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();
    }
}

答案 3 :(得分:1)

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

答案 4 :(得分:0)

This answer applies to Google Maps api v2.
It is possible by registering your application with Sensor Listener for Orientation and get the
angle relative to true north inside onSensorChanged and update camera accordingly.
Angle can be used for bearing. Following code can be used:

Instead of using Sensor.TYPE_ORIENTATION try using getOrinetation api. Sensor.TYPE_ORIENTATION
has been deprecated.

@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));

}