在 Android 中旋转 MapView

发布于 2024-08-12 23:28:01 字数 864 浏览 6 评论 0原文

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

I am writing an Android app where one of the features is that the map will rotate according to the compass (i.e. if the phone is pointing east, the map will be oriented so that the east side of the map is on top). Previous answers that I have found suggested over writing the onDraw() method in mapView, however, the api changed the method to final so it cannot be overwritten. As a result I have tried to overwrite the dispatchDraw() method like so:

Note:

-compass is a boolean that if true, rotate the view

-bearing is a float variable that has the degrees that the view should rotate

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

煞人兵器 2024-08-19 23:28:01

感谢 pheelicks 和 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_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
}

}

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

Thanks to pheelicks and Nikita Koksharov answers, I manage to turn on/off the rotation of a mapview according to the compass.

First you will need the two inner class of MapViewCompassDemo.java found at: Android_SDK_ Tools\add-ons\addon-google_apis-google-#\samples\MapsDemo\src\com\example\android\apis\view\

RotateView
SmoothCanvas

Extract the inner class RotateView to RotateView.java and add SmoothCanvas as a inner class of RotateView.java instead of 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>

The 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
}

}

Update:
Rotating Google MapView with Compass Example Project: https://www.dropbox.com/sh/c1encbc2lr63qd9/6C1C4hsrlT

摇划花蜜的午后 2024-08-19 23:28:01

来自文档:

protected voiddispatchDraw(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_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>

From the docs:

protected void dispatchDraw (Canvas canvas)

Called by draw to draw the child views. This may be overridden by derived classes to gain control just before its children are drawn (but after its own view has been drawn).

So overriding dispatchDraw is no good as the main map view has already been drawn

One solution might be to add the MapView as a child of another CustomView (a sub-class of ViewGroup) and then use the dispatchDraw method of CustomView to draw the MapView (now a child) rotated. So in xml you'd do something like:

<?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>
御弟哥哥 2024-08-19 23:28:01

它应该是这样的:

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

It should be something like this:

@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();
    }
}
墨洒年华 2024-08-19 23:28:01

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

Take a look at MapsDemo examples in ANDROID_SDK\add-ons\addon-google_apis-google_inc_-7\samples\MapsDemo. It has rotation map demo.

家住魔仙堡 2024-08-19 23:28:01

此答案适用于 Google Maps api v2
可以通过向传感器侦听器注册您的应用程序来定位并获取
onSensorChanged 内相对于正北的角度并相应更新相机。
角度可用于轴承。可以使用以下代码:

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

}

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

}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文