16

我正在编写一个 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();
}
4

5 回答 5

8

感谢 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 

地图布局.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>

地图活动

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

于 2012-08-25T22:50:55.603 回答
3

从文档:

受保护的无效dispatchDraw(帆布画布)

由 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_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>
于 2010-11-30T04:46:47.397 回答
1

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

而不是使用Sensor.TYPE_ORIENTATION尝试使用 getOrinetation api。Sensor.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));

}
于 2015-01-14T08:11:03.993 回答
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();
    }
}
于 2010-06-27T20:54:11.887 回答
1

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

于 2012-01-30T16:40:55.800 回答