it-swarm.com.ru

Google Maps Android API v2 - обнаружение касания на карте

Я не могу найти пример того, как перехватить прикосновение карты к новому API Карт Google v2.

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

65
Gaucho

@ape написал здесь ответ о том, как перехватить щелчки на карте, но мне нужно перехватить прикосновения, а затем он предложил следующую ссылку в комментарии к ответу: Как обрабатывать событие onTouch для карты в Google Map API v2 ? .

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

Вот это рабочий код:

Я создал класс MySupportMapFragment.Java

import com.google.Android.gms.maps.SupportMapFragment;
import Android.os.Bundle;
import Android.view.LayoutInflater;
import Android.view.View;
import Android.view.ViewGroup;

public class MySupportMapFragment extends SupportMapFragment {
    public View mOriginalContentView;
    public TouchableWrapper mTouchView;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
        mOriginalContentView = super.onCreateView(inflater, parent, savedInstanceState);
        mTouchView = new TouchableWrapper(getActivity());
        mTouchView.addView(mOriginalContentView);
        return mTouchView;
    }

    @Override
    public View getView() {
        return mOriginalContentView;
    }
}

Я даже создал класс TouchableWrapper.Java:

import Android.content.Context;
import Android.view.MotionEvent;
import Android.widget.FrameLayout;

public class TouchableWrapper extends FrameLayout {

    public TouchableWrapper(Context context) {
        super(context);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {

        switch (event.getAction()) {

            case MotionEvent.ACTION_DOWN:
                  MainActivity.mMapIsTouched = true;
                  break;

            case MotionEvent.ACTION_UP:
                  MainActivity.mMapIsTouched = false;
                  break;
        }
        return super.dispatchTouchEvent(event);
    }
}

В макете я заявляю это так:

<fragment xmlns:Android="http://schemas.Android.com/apk/res/Android"
          Android:id="@+id/mapFragment"
          Android:layout_width="match_parent"
          Android:layout_height="wrap_content"
          Android:layout_alignParentBottom="true"
          Android:layout_below="@+id/buttonBar"
          class="com.myFactory.myApp.MySupportMapFragment"
/>

Просто для проверки в основной деятельности я написал только следующее:

public class MainActivity extends FragmentActivity {
    public static boolean mMapIsTouched = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}
89
Gaucho

Вот простое решение, чтобы получить местоположение на основе выбора пользователя (нажмите на карту вариант)

  googleMap.setOnMapClickListener(new OnMapClickListener() {

            @Override
            public void onMapClick(LatLng arg0) {
                // TODO Auto-generated method stub
                Log.d("arg0", arg0.latitude + "-" + arg0.longitude);
            }
        });
42
Sampath Kumar

Эта функция и многое другое теперь поддерживаются :)

это примечание для разработчиков (выпуск 4636):

В августовском выпуске 2016 года представлен набор новых прослушивателей смены камеры для событий начала, окончания и окончания движения камеры. Вы также можете увидеть, почему камера движется, вызвана ли она жестами пользователя, встроенной анимацией API или движениями, контролируемыми разработчиком. Подробности см. В руководстве по событиям смены камеры: https://developers.google.com/maps/documentation/Android-api/events#camera-change-events

Также см. Примечания к выпуску: https://developers.google.com/maps/documentation/Android-api/releases#august_1_2016

вот фрагмент кода со страницы документации 

public class MyCameraActivity extends FragmentActivity implements
        OnCameraMoveStartedListener,
        OnCameraMoveListener,
        OnCameraMoveCanceledListener,
        OnCameraIdleListener,
        OnMapReadyCallback {

    private GoogleMap mMap;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my_camera);

        SupportMapFragment mapFragment =
            (SupportMapFragment) getSupportFragmentManager()
                    .findFragmentById(R.id.map);
        mapFragment.getMapAsync(this);
    }

    @Override
    public void onMapReady(GoogleMap map) {
        mMap = map;

        mMap.setOnCameraIdleListener(this);
        mMap.setOnCameraMoveStartedListener(this);
        mMap.setOnCameraMoveListener(this);
        mMap.setOnCameraMoveCanceledListener(this);

        // Show Sydney on the map.
        mMap.moveCamera(CameraUpdateFactory
                .newLatLngZoom(new LatLng(-33.87365, 151.20689), 10));
    }

    @Override
    public void onCameraMoveStarted(int reason) {

        if (reason == OnCameraMoveStartedListener.REASON_GESTURE) {
            Toast.makeText(this, "The user gestured on the map.",
                           Toast.LENGTH_SHORT).show();
        } else if (reason == OnCameraMoveStartedListener
                                .REASON_API_ANIMATION) {
            Toast.makeText(this, "The user tapped something on the map.",
                           Toast.LENGTH_SHORT).show();
        } else if (reason == OnCameraMoveStartedListener
                                .REASON_DEVELOPER_ANIMATION) {
            Toast.makeText(this, "The app moved the camera.",
                           Toast.LENGTH_SHORT).show();
        }
    }

    @Override
    public void onCameraMove() {
        Toast.makeText(this, "The camera is moving.",
                       Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onCameraMoveCanceled() {
        Toast.makeText(this, "Camera movement canceled.",
                       Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onCameraIdle() {
        Toast.makeText(this, "The camera has stopped moving.",
                       Toast.LENGTH_SHORT).show();
    }
}
21
A.Alqadomi

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

<FrameLayout
    Android:id="@+id/map_touch_layer"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent" />

mapTouchLayer.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            Utils.logDebug(TAG, "Map touched!");
            timeLastTouched = System.currentTimeMillis();
            return false; // Pass on the touch to the map or shadow layer.
        }
    });
8
Flyview

У Гаучо отличный ответ, и, увидев множество положительных отзывов, я мог бы нуждаться в другой реализации:

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

Я положил все в один класс, который можно использовать так:

mapFragment.setNonConsumingTouchListener(new TouchSupportMapFragment.NonConsumingTouchListener() {
    @Override
    public void onTouch(MotionEvent motionEvent) {
        switch (motionEvent.getActionMasked()) {
            case MotionEvent.ACTION_DOWN:
                // map is touched
                break;
            case MotionEvent.ACTION_UP:
                // map touch ended
                break;
            default:
                break;
            // use more cases if needed, for example MotionEvent.ACTION_MOVE
        }
    }
});

где mapfragment должен иметь тип TouchSupportMapFragment и в макете xml эта строка необходима:

<fragment class="de.bjornson.maps.TouchSupportMapFragment"
...

Вот класс:

package de.bjornson.maps;

import Android.content.Context;
import Android.os.Bundle;
import Android.view.LayoutInflater;
import Android.view.MotionEvent;
import Android.view.View;
import Android.view.ViewGroup;
import Android.widget.FrameLayout;

import com.google.Android.gms.maps.SupportMapFragment;

public class TouchSupportMapFragment extends SupportMapFragment {
    public View mOriginalContentView;
    public TouchableWrapper mTouchView;
    private NonConsumingTouchListener mListener;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
        mOriginalContentView = super.onCreateView(inflater, parent, savedInstanceState);
        mTouchView = new TouchableWrapper(getActivity());
        mTouchView.addView(mOriginalContentView);
        return mTouchView;
    }

    @Override
    public View getView() {
        return mOriginalContentView;
    }

    public void setNonConsumingTouchListener(NonConsumingTouchListener listener) {
        mListener = listener;
    }

    public interface NonConsumingTouchListener {
        boolean onTouch(MotionEvent motionEvent);
    }

    public class TouchableWrapper extends FrameLayout {

        public TouchableWrapper(Context context) {
            super(context);
        }

        @Override
        public boolean dispatchTouchEvent(MotionEvent event) {
            if (mListener != null) {
                mListener.onTouch(event);
            }
            return super.dispatchTouchEvent(event);
        }
    }
}
6
Björn Kechel

https://developers.google.com/maps/documentation/Android/reference/com/google/Android/gms/maps/GoogleMap.OnMapClickListener

Смотрите эту ссылку. Реализуйте интерфейс и заполните метод onMapClick() или что вам нужно, и установите правильную реализацию onMapClickListener.

public class YourActivity extends Activity implements OnMapClickListener {
    @Override
    protected void onCreate(Bundle icicle) { 
        super.onCreate(icicle);
        ...
        my_map.setOnMapClickListener(this)        
        ...
    }

    public void onMapClick (LatLng point) {
        // Do Something
    }
}
5
adarsh
  // Initializing
    markerPoints = new ArrayList<LatLng>();

    // Getting reference to SupportMapFragment of the activity_main
    SupportMapFragment sfm = (SupportMapFragment)getSupportFragmentManager().findFragmentById(R.id.map);

    // Getting Map for the SupportMapFragment
    map = sfm.getMap();

    // Enable MyLocation Button in the Map
    map.setMyLocationEnabled(true);

    // Setting onclick event listener for the map
    map.setOnMapClickListener(new OnMapClickListener() {

        @Override
        public void onMapClick(LatLng point) {

            // Already two locations
            if(markerPoints.size()>1){
                markerPoints.clear();
                map.clear();
            }

            // Adding new item to the ArrayList
            markerPoints.add(point);

            // Creating MarkerOptions
            MarkerOptions options = new MarkerOptions();

            // Setting the position of the marker
            options.position(point);


            if(markerPoints.size()==1){
                options.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_GREEN));
            }else if(markerPoints.size()==2){
                options.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED));
            }

            // Add new marker to the Google Map Android API V2
            map.addMarker(options);

            // Checks, whether start and end locations are captured
            if(markerPoints.size() >= 2){
                LatLng Origin = markerPoints.get(0);
                LatLng dest = markerPoints.get(1);

            //Do what ever you want with Origin and dest
            }
        }
    });
1
Pratibha Sarode

Для моно любителей:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Util;
using Android.Views;
using Android.Widget;
using Android.Gms.Maps;

namespace apcurium.MK.Booking.Mobile.Client.Controls
{
    public class TouchableMap : SupportMapFragment
    {
        public View mOriginalContentView;

        public TouchableWrapper Surface;

        public override View OnCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState)
        {
            mOriginalContentView = base.OnCreateView(inflater, parent, savedInstanceState);
            Surface = new TouchableWrapper(Activity);
            Surface.AddView(mOriginalContentView);
            return Surface;
        }

        public override View View
        {
            get
            {
                return mOriginalContentView;
            }
        }
    }

    public class TouchableWrapper: FrameLayout {

        public event EventHandler<MotionEvent> Touched;

        public TouchableWrapper(Context context) :
        base(context)
        {
        }

        public TouchableWrapper(Context context, IAttributeSet attrs) :
        base(context, attrs)
        {
        }

        public TouchableWrapper(Context context, IAttributeSet attrs, int defStyle) :
        base(context, attrs, defStyle)
        {
        }

        public override bool DispatchTouchEvent(MotionEvent e)
        {
            if (this.Touched != null)
            {
                this.Touched(this, e);
            }

            return base.DispatchTouchEvent(e);
        }
    }
}
1
Léon Pelletier

@Gaucho MySupportMapFragment, очевидно, будет использоваться некоторыми другими ферментами или действиями (где может быть больше элементов вида, чем фрагмента карты). Итак, как можно отправить это событие следующему фрагменту, где оно будет использоваться. Нужно ли нам снова написать интерфейс для этого?

0
user2201332

У меня есть более простое решение, отличное от TouchableWrapper, и оно работает с последней версией play-services-maps:10.0.1. Это решение использует только события карт и не использует настраиваемые представления. Не использует устаревшие функции и, скорее всего, будет иметь поддержку нескольких версий.

Во-первых, вам нужна переменная flag, которая хранится, если карта перемещается с помощью анимации или пользовательского ввода (этот код предполагает, что каждое движение камеры, которое не инициируется анимацией, запускается пользователем)

GoogleMap googleMap;
boolean movedByApi = false;

Ваш фрагмент или деятельность должны реализовывать GoogleMap.OnMapReadyCallback, GoogleMap.CancelableCallback

public class ActivityMap extends Activity implements OnMapReadyCallback, GoogleMap.CancelableCallback{
    ...
}

и это заставляет вас реализовывать методы onMapReady, onFinish, onCancel. И объект googleMap в onMapReady должен установить список событий для перемещения камеры

@Override
public void onMapReady(GoogleMap mMap) {
    //instantiate the map
    googleMap = mMap;

    [...]  // <- set up your map

    googleMap.setOnCameraMoveListener(new GoogleMap.OnCameraMoveListener() {
        @Override
        public void onCameraMove() {
            if (movedByApi) {
                Toast.makeText(ActivityMap.this, "Moved by animation", Toast.LENGTH_SHORT).show();

                [...] // <-- do something whe you want to handle api camera movement
            } else {
                Toast.makeText(ActivityMap.this, "Moved by user", Toast.LENGTH_SHORT).show();

                [...] // <-- do something whe you want to handle user camera movement
            }
        }
    });
}
@Override
public void onFinish() {
    //is called when the animation is finished
    movedByApi = false;
}
@Override
public void onCancel() {
    //is called when the animation is canceled (the user drags the map or the api changes to a ne position)
    movedByApi = false;
}

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

public void moveMapPosition(CameraUpdate cu, boolean animated){
    //activate the flag notifying that the map is being moved by the api
    movedByApi = true;
    //if its not animated, just do instant move
    if (!animated) {
        googleMap.moveCamera(cu);
        //after the instant move, clear the flag
        movedByApi = false;
    }
    else
        //if its animated, animate the camera
        googleMap.animateCamera(cu, this);
}

или просто каждый раз, когда вы перемещаете карту, активируйте флаг перед анимацией

movedByApi = true;
googleMap.animateCamera(cu, this);

Надеюсь, это поможет!

0
Sander Rito