зная, когда карта перестала прокручиваться (как "moveend" в JavaScript API) - PullRequest
11 голосов
/ 04 декабря 2010

Мне нужно определить, когда MapView был прокручен или увеличен, как событие «moveend» в API javascript.Я хотел бы подождать до тех пор, пока представление не перестанет двигаться, поэтому я могу определить, нужно ли мне запрашивать у моего сервера элементы внутри прямоугольника просмотра и, если это так, отправлять запрос.(на самом деле я отправляю запрос на площадь немного большую, чем у прямоугольника просмотра)

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

В настоящее время я создаю подкласс MapView и обрабатываю onTouchEvent следующим образом:

 public boolean onTouchEvent(android.view.MotionEvent ev) {
        super.onTouchEvent (ev);
        if (ev.getAction() == MotionEvent.ACTION_UP) {
            GeoPoint center = getMapCenter();
            int latSpan = getLatitudeSpan(), lngSpan = getLongitudeSpan();
            /* (check if it has moved enough to need a new set of data)  */    
        }
        return true;
    }

Проблема в том, что я не знаю, остановилось ли представление, поскольку прокрутка имеет тенденцию иметь инерцию и может продолжать проходить после события "ACTION_UP".

Есть ли какое-либо событие, к которому я могу подключиться,предупредить меня, когда просмотр карты будет перемещен (или увеличен)?Если нет, кто-нибудь написал логику, чтобы обнаружить это?Теоретически я мог бы сделать предположение, посмотрев на все действия, и назначить что-нибудь, чтобы прийти немного позже, и проверить это ... но ... это кажется грязным и PITA.Но если кто-то уже написал это ....:)

Ответы [ 5 ]

13 голосов
/ 16 сентября 2011

Это метод, который я использую в данный момент, я использовал его и проверил, работает хорошо.Просто убедитесь, что ваш метод draw() эффективен.(Избегайте GC в нем).

//In map activity

class MyMapActivity extends MapActivity {


  protected void onCreate(Bundle savedState){
    setContent(R.layout.activity_map);
    super.onCreate(savedSate);

    OnMapMoveListener mapListener = new OnMapMoveListener(){
      public void mapMovingFinishedEvent(){
        Log.d("MapActivity", "Hey look! I stopped scrolling!");
      }
    }

    // Create overlay
    OnMoveOverlay mOnMoveOverlay = new OnMoveOverlay(mapListener);

    // Add overlay to view.
    MapView mapView = (MapView)findViewById(R.id.map_view);

    // Make sure you add as the last overlay so its on the top. 
    // Otherwise other overlays could steal the touchEvent;
    mapView.getOverlays().add(mOnMoveOverlay);
  }

}

Это ваш класс OnMoveOverlay

//OnMoveOverlay

class OnMoveOverlay extends Overlay
{

    private static GeoPoint lastLatLon = new GeoPoint(0, 0);
    private static GeoPoint currLatLon;

            // Event listener to listen for map finished moving events
            private OnMapMoveListener eventListener = null;

    protected boolean isMapMoving = false;

            public OnMoveOverlay(OnMapMoveListener eventLis){
              //Set event listener
              eventListener = eventLis;
            }

    @Override  
    public boolean onTouchEvent(android.view.MotionEvent ev)
    {
        super.onTouchEvent(ev);
        if (ev.getAction() == MotionEvent.ACTION_UP)
        {
            // Added to example to make more complete
            isMapMoving = true;
        }
        //Fix: changed to false as it would handle the touch event and not pass back.
        return false;
    }

    @Override  
    public void draw(Canvas canvas, MapView mapView, boolean shadow)
    {
        if (!shadow)
        {
            if (isMapMoving)
            {
                currLatLon = mapView.getProjection().fromPixels(0, 0);
                if (currLatLon.equals(lastLatLon))
                {
                    isMapMoving = false;
                    eventListener.mapMovingFinishedEvent();
                }
                else
                {
                    lastLatLon = currLatLon;
                }
            }
        }
    }

            public interface OnMapMoveListener{
                public void mapMovingFinishedEvent();
            }
}

Просто реализуйте свой собственный слушатель eventListener.mapMovingFinishedEvent(); и запустите перемещение по карте с помощью другого метода, подобного описанному выше, и ваш отсортированный.

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

Я обновил это с более новым более полным кодом, былС этим связано двойное рисование.

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

Не стесняйтесь задавать любые вопросы :)

Спасибо, Крис

8 голосов
/ 21 марта 2011

У меня была та же проблема, и я «решил» ее аналогичным образом, но я думаю, что она менее сложная: поскольку переопределение computeScroll () не сработало для меня, я также переопределил метод TouchTvent.Затем я использовал обработчик, который вызывает вызов метода через 50 мс, если центр карты изменился, то же самое происходит снова, если центр карты не изменился, вызывается слушатель.Метод, который я вызываю в onTouchEvent, выглядит следующим образом:

private void refreshMapPosition() {
    GeoPoint currentMapCenter = getMapCenter();
    if (oldMapCenter==null || !oldMapCenter.equals(currentMapCenter)) {
        oldMapCenter = currentMapCenter;
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                refreshMapPosition();
            }
        }, 50);
    }
    else {
        if (onScrollEndListener!=null)
            onScrollEndListener.onScrollEnd(currentMapCenter);
    }
}

Но я тоже жду реального решения для этого ...

2 голосов
/ 13 ноября 2012

Я решил это с помощью потока, и это, кажется, работает довольно хорошо.Он не только обнаруживает изменения центра, но и изменения масштаба.Что ж, обнаружение выполняется после завершения масштабирования и прокрутки.Если вам нужно обнаружить изменения масштабирования при перемещении вверх по первому пальцу, то вы можете немного изменить мой код, чтобы обнаружить разные указатели.Но я не нуждался в этом, поэтому не включил его и оставил домашнюю работу для вас: D

public class CustomMapView extends MapView {

    private GeoPoint pressGP;
    private GeoPoint lastGP;

    private int pressZoom;
    private int lastZoom;

    public boolean onTouchEvent( MotionEvent event ) {
        switch( event.getAction() ) {
            case MotionEvent.ACTION_DOWN:
                pressGP = getMapCenter();
                pressZoom = getZoomLevel();
                break;
            case MotionEvent.ACTION_UP:
                lastGP = getMapCenter();
                pressZoom = getZoomLevel();

                if( !pressGP.equals( lastGP ) ) {
                    Thread thread = new Thread() {
                        public void run() {
                            while( true ) {
                                try {
                                    Thread.sleep( 100 );
                                } catch (InterruptedException e) {}

                                GeoPoint gp = getMapCenter();
                                int zl = getZoomLevel();
                                if( gp.equals( lastGP ) && zl == lastZoom)
                                break;
                                lastGP = gp;
                                lastZoom = zl;
                            }

                            onMapStop( lastGP );
                        }
                    };
                    thread.start();
                }
                break;

        }

        return super.onTouchEvent( event );
    }

    public void onMapStop( GeoPoint point , int zoom ){
        // PUT YOUR CODE HERE
    }
}
2 голосов
/ 25 января 2011

У меня нет удовлетворительного решения этой проблемы, но я могу сказать, что я сделал, чтобы частично ее решить.

  • Я вложил в подкласс MapView и переопределил метод computeScroll(), который получает текущую центральную точку карты и сравнивает ее с последней известной центральной точкой (сохраненной как поле volatile в подклассе). Если центральная точка изменилась, она запускает событие для слушателя карты (для этого я определил пользовательский интерфейс слушателя).
  • Слушатель - это действие, которое создает подкласс AsyncTask и выполняет его. Эта задача приостанавливается на 100 мс в методе doInBackGround() перед выполнением выборки данных с сервера.
  • Когда действие слушателя получает второе событие перемещения карты (что оно будет делать из-за эффекта пошагового перемещения карты), оно проверяет состояние только что выполненного AsyncTask. Если эта задача все еще выполняется, она будет cancel(). Затем он создает новую задачу и выполняет ее.

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

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

1 голос
/ 19 марта 2016

В последней версии API карт Google (V2) для этого есть слушатель, т. Е. GoogleMap.OnCameraChangeListener.

mGoogleMap.setOnCameraChangeListener(new GoogleMap.OnCameraChangeListener()
{
    @Override
    public void onCameraChange(CameraPosition cameraPosition)
    {
        Toast.makeText(mActivity, "Longitude : "+cameraPosition.target.longitude
                +", Latitude : "+cameraPosition.target.latitude, Toast.LENGTH_SHORT).show();
    }
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...