【问题标题】:On zoom event for google maps on android关于android上谷歌地图的缩放事件
【发布时间】:2011-01-02 01:49:27
【问题描述】:

我们正在构建一个使用 google maps api for android 的应用程序。

我有我的 MapController 和 MapView,我使用以下方法启用内置缩放控件:

mapView.setBuiltInZoomControls(true);

我现在想在用户实际放大地图时获得一个事件,我该怎么做?我找不到可以检测到缩放级别变化的此类事件或任何一般事件。

更新

The mapView.getZoomControls() is deprecated。并且文档建议改用 mapView.setBuiltInZoomControls(bool) 。这没关系,但我根本无法弄清楚如何对内置缩放控件的事件采取行动。

【问题讨论】:

  • 为了同样的目的,我尝试实现 onUserInteraction 事件,但我仍然遇到问题。我正在显示一个需要根据缩放级别缩放的图像,所以显然我想在用户缩放时调用它的 redraw() 方法。我的问题是,当用户单击缩放按钮时会调用 onUserInteraction,因此 zoomLevel 尚未更新,仅在下一次交互(单击、跨度等)时才更新 zoomLevel。因此,我的图像仅在实际缩放后的交互后更新。有什么想法吗?
  • 这个问题和答案是指API v1,我在下面添加了一个新的答案谁在使用Google Maps Android API v2

标签: java android events google-maps zooming


【解决方案1】:

借助 Google Maps Android API v2,您可以像这样使用GoogleMap.OnCameraChangeListener

mMap.setOnCameraChangeListener(new OnCameraChangeListener() {

    private float currentZoom = -1;

    @Override
    public void onCameraChange(CameraPosition pos) {
        if (pos.zoom != currentZoom){
            currentZoom = pos.zoom;
            // do you action here
        }
    }
});

【讨论】:

  • setOnCameraChangeListener() 现已弃用
【解决方案2】:

您可以使用 android Handler 实现自己的缩放值基本“轮询”,以检测缩放何时更改。

为您的可运行事件使用以下代码。这是您应该进行处理的地方。

private Handler handler = new Handler();

public static final int zoomCheckingDelay = 500; // in ms

private Runnable zoomChecker = new Runnable()
{
    public void run()
    {
        checkMapIcons();

        handler.removeCallbacks(zoomChecker); // remove the old callback
        handler.postDelayed(zoomChecker, zoomCheckingDelay); // register a new one
    }
};

启动回调事件使用

protected void onResume()
{
    super.onResume();
    handler.postDelayed(zoomChecker, zoomCheckingDelay);
}

并在您离开活动时使用

停止
protected void onPause()
{
    super.onPause();
    handler.removeCallbacks(zoomChecker); // stop the map from updating
}

文章如果您想要更长的文章,可以找到here

【讨论】:

  • 我已将赏金授予此答案,因为这是确定地图是否已移动或缩放的最简单方法。
【解决方案3】:

我使用这个库,它有一个 onZoom 函数监听器。 http://code.google.com/p/mapview-overlay-manager/。效果很好。

【讨论】:

  • 听起来很有希望。我会仔细看看!
【解决方案4】:

正如 OP 所说,使用 onUserInteractionEvent 并自己进行测试。

【讨论】:

  • onUserInteractionEvent() 在缩放级别更改之前被调用。这实际上意味着,对于每个缩放事件,监控缩放的应用程序都会在后面运行一个事件。
  • @Paul:嗨。本来我没有考虑到这一点,但看来你是对的,我展示的吐司总是落后一个。
  • 您可以创建一个Handler 实例并通过postDelayed(new Runnable() {...}, 500) 之类的方式定期检查缩放级别的变化,但我真的不喜欢这种解决方案。
【解决方案5】:

这是一个干净的解决方案。只需将此 TouchOverlay 私有类添加到您的 Activity 和一个名为 onZoom 的方法(由该内部类调用)。

注意,您必须将此 TouchOverlay 添加到您的 mapView 中,例如

mapView.getOverlays().add(new TouchOverlay());

每当用户触摸地图时,它都会跟踪缩放级别,例如双击或捏缩放,然后在缩放级别发生变化时触发 onZoom 方法(使用缩放级别)。

   private class TouchOverlay extends com.google.android.maps.Overlay {
            int lastZoomLevel = -1;

            @Override
            public boolean onTouchEvent(MotionEvent event, MapView mapview) {
                if (event.getAction() == 1) {
                    if (lastZoomLevel == -1)
                        lastZoomLevel = mapView.getZoomLevel();

                    if (mapView.getZoomLevel() != lastZoomLevel) {
                        onZoom(mapView.getZoomLevel());
                        lastZoomLevel = mapView.getZoomLevel();
                    }
                }
                return false;
            }
        }

        public void onZoom(int level) {
            reloadMapData(); //act on zoom level change event here
        }

【讨论】:

  • 通过您的解决方案,我能够轻松捕捉缩放变化!谢谢
  • 出色的解决方案,但是它没有检测到缩放的第一次变化。删除 -1 的第一个 if 语句解决了这个问题。
【解决方案6】:

android API 建议您使用具有 setOnZoomInClickListener() 的 ZoomControls

要添加这些缩放控件,您可以:

ZoomControls mZoom = (ZoomControls) mapView.getZoomControls();

然后将 mZoom 添加到您的布局中。

【讨论】:

  • 感谢您的回答。 MapView.getZoomControls() 已弃用,建议使用 MapView.setBuiltInZoomControls(boolean) 方法。但是我找不到任何地方可以从这些内置缩放控件中获取任何事件。参考:code.google.com/android/add-ons/google-apis/reference/com/….
  • 我明白了。好吧,看起来您可以使用未记录的 mapView.getZoomButtonsController(),在 code.google.com/p/android/issues/detail?id=3348 中进行了描述,否则您只需要使用 mapview.onkeydown 并测试缩放。
  • 我使用 onUserInteraction 事件得到了我想要的,并手动测试缩放级别的变化。使用 toast 消息通知用户必须放大以查看我的叠加层时,它的效果非常好。
【解决方案7】:

你可以使用

ZoomButtonsController zoomButton = mapView.getZoomButtonsController();
zoomButton.setOnZoomListener(listener);

希望对你有帮助

【讨论】:

  • 这非常具体地回答了 OP 的问题,但仅通过缩放按钮引发了缩放事件的事件。例如,捏住不会调用侦听器的回调。
【解决方案8】:

我认为这个问题可能还有另一个答案。 Overlay 类绘制方法在任何缩放后调用,我相信这是在缩放级别更改后调用的。您不能构建您的应用程序来利用这一点吗?如果您愿意,您甚至可以使用虚拟覆盖层来检测这一点。这不会比使用延迟的可运行对象更有效吗?

@Override
public boolean draw (Canvas canvas, MapView mapView, boolean shadow, long when) {
    int zoomLevel = mapView.getZoomLevel();
    // do what you want with the zoom level
    return super.draw(canvas, mapView, shadow, when);
}

【讨论】:

    【解决方案9】:

    你可以像这样拥有 Zoom CControl。

    这里我附上你如何实现缩放控制的代码。

    1>> XML 文件应该是这样的。

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
        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:enabled="true"
            android:clickable="true"
            android:apiKey="0l4sCTTyRmXTNo7k8DREHvEaLar2UmHGwnhZVHQ"
            />
    
        <LinearLayout android:id="@+id/zoom" 
            android:layout_width="wrap_content" 
            android:layout_height="wrap_content" 
            android:layout_alignParentBottom="true" 
            android:layout_centerHorizontal="true" 
            /> 
    
    </RelativeLayout>
    

    2>> 在 oncreate 方法中的主要活动上,请执行以下操作。 在这里,您正在使用 mapView 膨胀您的视图

    mapView = (MapView) findViewById(R.id.mapView);
            LinearLayout zoomLayout = (LinearLayout)findViewById(R.id.zoom);  
            View zoomView = mapView.getZoomControls(); 
    
            zoomLayout.addView(zoomView, 
                new LinearLayout.LayoutParams(
                    LayoutParams.WRAP_CONTENT, 
                    LayoutParams.WRAP_CONTENT)); 
            mapView.displayZoomControls(true);
    

    .................................................. ………… 这就是您可以使用 API 的内置缩放控制的方式。

    您可以拥有自己的自定义代码来实现像这样的放大和缩小...

    public boolean onKeyDown(int keyCode, KeyEvent event) 
    {
        MapController mc = mapView.getController(); 
        switch (keyCode) 
        {
            case KeyEvent.KEYCODE_3:
                mc.zoomIn();
                break;
            case KeyEvent.KEYCODE_1:
                mc.zoomOut();
                break;
        }
        return super.onKeyDown(keyCode, event);
    }    
    

    ..这就是我的实现方式...

    谢谢..Rakesh

    【讨论】:

      【解决方案10】:

      对于 V2.0 之前的版本,我创建了一个扩展 MapView 的类,当地图区域开始变化 (onRegionBeginChange) 和停止变化 (onRegionEndChange) 时,它会向侦听器发出警报。

      import android.content.Context;
      import android.util.AttributeSet;
      import android.view.MotionEvent;
      
      import com.google.android.maps.GeoPoint;
      import com.google.android.maps.MapView;
      
      public class ExMapView extends MapView {
          private static final String TAG = ExMapView.class.getSimpleName();
          private static final int DURATION_DEFAULT = 700;
      
          private OnRegionChangedListener onRegionChangedListener;
          private GeoPoint previousMapCenter;
          private int previousZoomLevel;
          private int changeDuration; // This is the duration between when the user stops moving the map around and when the onRegionEndChange event fires.
          private boolean isTouched = false;
          private boolean regionChanging = false;
      
          private Runnable onRegionEndChangeTask = new Runnable() {
              public void run() {
                  regionChanging = false;
                  previousMapCenter = getMapCenter();
                  previousZoomLevel = getZoomLevel();
                  if (onRegionChangedListener != null) {
                      onRegionChangedListener.onRegionEndChange(ExMapView.this, previousMapCenter, previousZoomLevel);
                  }
              }
          };
      
          public ExMapView(Context context, AttributeSet attrs) {
              super(context, attrs);
              init();
          }
      
          public ExMapView(Context context, AttributeSet attrs, int defStyle) {
              super(context, attrs, defStyle);
              init();
          }
      
          public ExMapView(Context context, String apiKey) {
              super(context, apiKey);
              init();
          }
      
          @Override
          public boolean onTouchEvent(MotionEvent event) {
              isTouched = event.getAction() != MotionEvent.ACTION_UP;
              return super.onTouchEvent(event);
          }
      
          @Override
          public void computeScroll() {
              super.computeScroll();
      
              // If the map region is still changing (user is still scrolling or zooming), reset timer for onRegionEndChange.
              if ((!isTouched && !getMapCenter().equals(previousMapCenter)) || (previousZoomLevel != getZoomLevel())) {
      
                  // If the region has just begun changing, fire off onRegionBeginChange event.
                  if (!regionChanging) {
                      regionChanging = true;
                      if (onRegionChangedListener != null) {
                          onRegionChangedListener.onRegionBeginChange(this, previousMapCenter, previousZoomLevel);
                      }
                  }
      
                  // Reset timer for onRegionEndChange.
                  removeCallbacks(onRegionEndChangeTask);
                  postDelayed(onRegionEndChangeTask, changeDuration);
              }
          }
      
          private void init() {
              changeDuration = DURATION_DEFAULT;
              previousMapCenter = getMapCenter();
              previousZoomLevel = getZoomLevel();
          }
      
          public void setOnRegionChangedListener(OnRegionChangedListener listener) {
              onRegionChangedListener = listener;
          }
      
          public void setChangeDuration(int duration) {
              changeDuration = duration;
          }
      
          public interface OnRegionChangedListener {
              public abstract void onRegionBeginChange(ExMapView exMapView, GeoPoint geoPoint, int zoomLevel);
              public abstract void onRegionEndChange(ExMapView exMapView, GeoPoint geoPoint, int zoomLevel);
          }
      }
      

      【讨论】:

        【解决方案11】:

        我混合使用了上述方法。我发现使用定时器每半秒启动一个线程会导致地图非常糟糕。可能是因为我每次都使用几个 If 语句。因此,我在 onUserInteraction 的 500 毫秒后延迟上启动了线程。这为 zoomLevel 提供了足够的时间在线程开始运行之前进行更新,从而无需每 500 毫秒运行一次线程即可获得正确的缩放级别。

        public void onUserInteraction() {
            handler.postDelayed(zoomChecker, zoomCheckingDelay);
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-11-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多