在 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_ORIENTATION
。 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));
【讨论】:
有什么办法可以改变旋转轴吗?以上是关于在 Android 中旋转 MapView的主要内容,如果未能解决你的问题,请参考以下文章