Как узнать, что панорамирование и масштабирование карты действительно завершены?

Я пытаюсь написать приложение, которое будет динамически загружать данные для отображения, пока пользователь перемещает или увеличивает их.

Мне нужно отследить, когда карта закончена, чтобы изменить ее состояние просмотра (останавливает панорамирование или масштабирование), а затем загрузить новую порцию данных для создания маркеров. Но на самом деле у API Карт Google нет событий, чтобы справиться с этим.

Есть несколько методов, таких как создание пустого наложения для управления событиями onTouch и так далее, но панорамирование карты могло продолжаться долго после того, как пользователь закончил свое касание, потому что GMaps используют некоторую инерцию, чтобы сделать панорамирование более плавным.

Я попытался создать подкласс MapView , но его метод draw () является окончательным , поэтому его нельзя переопределить.

Есть идеи, как сделать точную обработку панорамирования и масштабирования?

10
задан the Tin Man 9 April 2012 в 18:57
поделиться

1 ответ

Часы исследований и какое-то решение было найдено. У него есть свои минусы и плюсы, о которых я расскажу дальше.

Главное, что нам нужно сделать, это переопределить некоторые методы MapView, чтобы управлять его поведением при отрисовке. В случае, если мы не можем переопределить метод draw(), мы должны найти другой путь. Существует еще одна производная от View, которая может быть переопределена - метод calculateScroll(). Он вызывается повторно, поскольку карта продолжает заполняться. Все, что нам нужно сделать, это установить некоторый временной порог, чтобы поймать, если в этот раз больше не будет вызываться calculateScroll.
Вот что я сделал:

import java.util.Timer;
import java.util.TimerTask;

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 EnhancedMapView extends MapView {
public interface OnZoomChangeListener {
    public void onZoomChange(MapView view, int newZoom, int oldZoom);
}

public interface OnPanChangeListener {
    public void onPanChange(MapView view, GeoPoint newCenter, GeoPoint oldCenter);
}

private EnhancedMapView _this;

    // Set this variable to your preferred timeout
private long events_timeout = 500L;
private boolean is_touched = false;
private GeoPoint last_center_pos;
private int last_zoom;
private Timer zoom_event_delay_timer = new Timer();
private Timer pan_event_delay_timer = new Timer();

private EnhancedMapView.OnZoomChangeListener zoom_change_listener;
private EnhancedMapView.OnPanChangeListener pan_change_listener;


public EnhancedMapView(Context context, String apiKey) {
    super(context, apiKey);
    _this = this;
    last_center_pos = this.getMapCenter();
    last_zoom = this.getZoomLevel();
}

public EnhancedMapView(Context context, AttributeSet attrs) {
    super(context, attrs);
}

public EnhancedMapView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
}

public void setOnZoomChangeListener(EnhancedMapView.OnZoomChangeListener l) {
    zoom_change_listener = l;
}

public void setOnPanChangeListener(EnhancedMapView.OnPanChangeListener l) {
    pan_change_listener = l;
}

@Override
public boolean onTouchEvent(MotionEvent ev) {
    if (ev.getAction() == 1) {
        is_touched = false;
    } else {
        is_touched = true;
    }

    return super.onTouchEvent(ev);
}

@Override
public void computeScroll() {
    super.computeScroll();

    if (getZoomLevel() != last_zoom) {
                    // if computeScroll called before timer counts down we should drop it and start it over again
        zoom_event_delay_timer.cancel();
        zoom_event_delay_timer = new Timer();
        zoom_event_delay_timer.schedule(new TimerTask() {
            @Override
            public void run() {
                zoom_change_listener.onZoomChange(_this, getZoomLevel(), last_zoom);
                last_zoom = getZoomLevel();
            }
        }, events_timeout);
    }

    // Send event only when map's center has changed and user stopped touching the screen
    if (!last_center_pos.equals(getMapCenter()) || !is_touched) {
        pan_event_delay_timer.cancel();
        pan_event_delay_timer = new Timer();
        pan_event_delay_timer.schedule(new TimerTask() {
            @Override
            public void run() {
                pan_change_listener.onPanChange(_this, getMapCenter(), last_center_pos);
                last_center_pos = getMapCenter();
            }
        }, events_timeout);
    }
}

}

Затем вы должны зарегистрировать обработчики событий в MapActivity следующим образом:

public class YourMapActivity extends MapActivity {

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    mv = new EnhancedMapView(this, "<your Maps API key here>");

    mv.setClickable(true);
    mv.setBuiltInZoomControls(true);

    mv.setOnZoomChangeListener(new EnhancedMapView.OnZoomChangeListener() {
        @Override
        public void onZoomChange(MapView view, int newZoom, int oldZoom) {
            Log.d("test", "zoom changed from " + oldZoom + " to " + newZoom);
        }
    }
    mv.setOnPanChangeListener(new EnhancedMapView.OnPanChangeListener() {
        public void onPanChange(MapView view, GeoPoint newCenter, GeoPoint oldCenter) {
            Log.d("test", "center changed from " + oldCenter.getLatitudeE6() + "," + oldCenter.getLongitudeE6() + " to " + newCenter.getLatitudeE6() + "," + newCenter.getLongitudeE6());
        }
    }
}

А как насчет преимуществ и недостатков такого подхода?
Преимущества:
- События обрабатываются в зависимости от того, как карта была панорамирована или увеличена. Обрабатываются события касания, используемые аппаратные клавиши, даже программно запускаемые события (например, методы setZoom() или animate()).
- Возможность пропустить ненужную загрузку данных, если пользователь быстро нажимает кнопку масштабирования несколько раз. Событие сработает только после прекращения кликов.
Недостатки:
- Совершенно невозможно отменить действие масштабирования или панорамирования (возможно, я добавлю эту возможность в будущем)

Надеюсь, этот небольшой класс поможет вам.

12
ответ дан 4 December 2019 в 00:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: