Как я могу обработать перенос карты с помощью Google Maps для Android V2?

Я хочу указать адрес геокода, как только будет изменен центр карты.

Как я могу обрабатывать перемещение карты с помощью новых карт Google для Android V2? (Я говорю о случае, тогда пользователь перетаскивает карту пальцем)

Ответ 1

Ниже приведено возможное обходное решение для определения начальных и конечных событий перетаскивания:

Вам нужно расширить SupportMapFragment или MapFragment. В onCreateView вы должны обернуть свой MapView в настраиваемом FrameLayout (в примере ниже он является классом TouchableWrapper), в котором вы перехватываете события касания и узнаете, используется ли карта или нет. Если вы вызываете "onCameraChange", просто проверьте, нажато ли отображение карты или нет (в примере ниже это переменная "mMapIsTouched" ).

Пример кода:

ОБНОВЛЕНИЕ 1:

  • вернуть исходное созданное представление в getView()
  • используйте dispatchTouchEvent() вместо onInterceptTouchEvent()

Пользовательский FrameLayout:

private class TouchableWrapper extends FrameLayout {

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {

        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mMapIsTouched = true;
                break;
            case MotionEvent.ACTION_UP:
                mMapIsTouched = false;
                break;
        }

        return super.dispatchTouchEvent(ev);

    }

}

В вашем настроенном MapFragment:

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

В вашем методе обратного вызова камеры:

private final OnCameraChangeListener mOnCameraChangeListener = 
        new OnCameraChangeListener() {

    @Override
    public void onCameraChange(CameraPosition cameraPosition) {
        if (!mMapIsTouched) {
            refreshClustering(false);
        }
    }
};

Ответ 2

Ознакомьтесь с новыми картами api.

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

developers.google.com образец

Ответ 3

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

Код можно найти на Github по этой ссылке: https://github.com/MadsFrandsen/MapStateListener

Мое решение можно использовать из действия следующим образом:

new MapStateListener(mMap, mMapFragment, this) {
  @Override
  public void onMapTouched() {
    // Map touched
  }

  @Override
  public void onMapReleased() {
    // Map released
  }

  @Override
  public void onMapUnsettled() {
    // Map unsettled
  }

  @Override
  public void onMapSettled() {
    // Map settled
  }
};

Ответ 4

Я бы попробовал onCameraChangeListener. Слушатель вызывается каждый раз, когда движение камеры завершено. Слушатель также предоставит вам новое место. В моих тестах слушатель часто вызывался во время перетаскивания, может быть, есть лучшее решение.

Ответ 5

Начиная с игровых сервисов-карт 9.4.0 вы можете просто использовать GoogleMap.OnCameraMoveStartedListener, GoogleMap.OnCameraMoveListener и GoogleMap.OnCameraIdleListener.

Если по какой-то причине вы хотите использовать старый API, который теперь устарел, вы можете использовать onCameraChangeListener. Но вы должны знать две вещи:

  • onCameraChange() может вызываться много раз, пока вы перетаскиваете карту ИЛИ только один раз (при перетаскивании).
  • Положение камеры в последнем вызове onCameraChange() может немного отличаться от конечной позиции камеры.

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

private static final int MESSAGE_ID_SAVE_CAMERA_POSITION = 1;
private static final int MESSAGE_ID_READ_CAMERA_POSITION = 2;
private CameraPosition lastCameraPosition;
private Handler handler;
private GoogleMap googleMap;

public void onMapReady(GoogleMap theGoogleMap) {
    googleMap = theGoogleMap;

    handler = new Handler() {
        public void handleMessage(Message msg) {
            if (msg.what == MESSAGE_ID_SAVE_CAMERA_POSITION) {
                lastCameraPosition = googleMap.getCameraPosition();
            } else if (msg.what == MESSAGE_ID_READ_CAMERA_POSITION) {
                if (lastCameraPosition.equals(googleMap.getCameraPosition())) {
                    Log.d(LOG, "Camera position stable");
                }
            }
        }
    };

    googleMap.setOnCameraChangeListener(new GoogleMap.OnCameraChangeListener() {
        @Override
        public void onCameraChange(CameraPosition cameraPosition) {
            handler.removeMessages(MESSAGE_ID_SAVE_CAMERA_POSITION);
            handler.removeMessages(MESSAGE_ID_READ_CAMERA_POSITION);
            handler.sendEmptyMessageDelayed(MESSAGE_ID_SAVE_CAMERA_POSITION, 300);
            handler.sendEmptyMessageDelayed(MESSAGE_ID_READ_CAMERA_POSITION, 600);
        }
    });
}

Ответ 6

Мне нужно оживить мой маркер до центра, пока пользователь перетаскивает карту. Я реализовал его с помощью ответа Стаса Шакирова

MapDragListenerFragment.class

public class MapDragListenerFragment extends Fragment implements OnMapReadyCallback, GoogleMap.OnMapLoadedCallback {

    private Context mContext;
    private SupportMapFragment supportMapFragment;
    private Marker centerMarker;
    private LatLng mapCenterLatLng;
    private TextView tvLocationName;
    private Button btnFinalizeDestination;
    private GoogleMap mGoogleMap;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_map_drag_listener, container, false);
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        mContext = getActivity();

        tvLocationName = (TextView) view.findViewById(R.id.tv_location_name);
    }

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

        FragmentManager fm = getActivity().getSupportFragmentManager();//getChildFragmentManager();//
        supportMapFragment = (SupportMapFragment) fm.findFragmentById(R.id.map_container);
        if (supportMapFragment == null) {
            //// FIXME: 2/13/2017 crashes at casting to TouchableMapFragment
            supportMapFragment = SupportMapFragment.newInstance();
            fm.beginTransaction().replace(R.id.map_container, supportMapFragment).commit();
        }
        supportMapFragment.getMapAsync(this);

    }

    @Override
    public void onMapReady(GoogleMap googleMap) {

        if (googleMap != null) {
            mGoogleMap = googleMap;

            centerMarker = mGoogleMap.addMarker(new MarkerOptions().position(mGoogleMap.getCameraPosition().target)
                    .title("Center of Map")
                    .icon(BitmapDescriptorFactory.fromResource(R.drawable.end_green)));

            mGoogleMap.setOnCameraIdleListener(new GoogleMap.OnCameraIdleListener() {
                @Override
                public void onCameraIdle() {
                    mapCenterLatLng = mGoogleMap.getCameraPosition().target;

                    animateMarker(centerMarker,mapCenterLatLng,false);

                    Toast.makeText(mContext, "The camera has stopped moving.",
                            Toast.LENGTH_SHORT).show();

                    String address = getCompleteAddressString(mapCenterLatLng.longitude,mapCenterLatLng.longitude);
                    tvLocationName.setText(address);
                }
            });
            mGoogleMap.setOnCameraMoveStartedListener(new GoogleMap.OnCameraMoveStartedListener() {
                @Override
                public void onCameraMoveStarted(int reason) {
                    if (reason == GoogleMap.OnCameraMoveStartedListener.REASON_GESTURE) {
                        ///tvLocationName.setText("Lat " + mapCenterLatLng.latitude + "  Long :" + mapCenterLatLng.longitude);
                        Toast.makeText(mContext, "The user gestured on the map.",
                                Toast.LENGTH_SHORT).show();
                    } else if (reason == GoogleMap.OnCameraMoveStartedListener
                            .REASON_API_ANIMATION) {
                        Toast.makeText(mContext, "The user tapped something on the map.",
                                Toast.LENGTH_SHORT).show();
                    } else if (reason == GoogleMap.OnCameraMoveStartedListener
                            .REASON_DEVELOPER_ANIMATION) {
                        Toast.makeText(mContext, "The app moved the camera.",
                                Toast.LENGTH_SHORT).show();
                    }
                }
            });
            mGoogleMap.setOnCameraMoveListener(new GoogleMap.OnCameraMoveListener() {
                @Override
                public void onCameraMove() {
                    Toast.makeText(mContext, "The camera is moving.",
                            Toast.LENGTH_SHORT).show();
                }
            });
            mGoogleMap.setOnCameraMoveCanceledListener(new GoogleMap.OnCameraMoveCanceledListener() {
                @Override
                public void onCameraMoveCanceled() {
                    Toast.makeText(mContext, "Camera movement canceled.",
                            Toast.LENGTH_SHORT).show();
                }
            });

            mapCenterLatLng = mGoogleMap.getCameraPosition().target;// it should be done on MapLoaded.

            if (ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION) !=
                    PackageManager.PERMISSION_GRANTED &&
                    ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_COARSE_LOCATION) !=
                            PackageManager.PERMISSION_GRANTED) {
                return;
            }
            mGoogleMap.setMyLocationEnabled(true);
            mGoogleMap.animateCamera(CameraUpdateFactory.zoomTo(15));

            mGoogleMap.setOnMapLoadedCallback(this);
            mGoogleMap.setOnCameraMoveListener(new GoogleMap.OnCameraMoveListener() {
                @Override
                public void onCameraMove() {

                }
            });
        }
    }

    public void animateMarker(final Marker marker, final LatLng toPosition,
                              final boolean hideMarker) {
        final Handler handler = new Handler();
        final long start = SystemClock.uptimeMillis();
        Projection proj = mGoogleMap.getProjection();
        Point startPoint = proj.toScreenLocation(marker.getPosition());
        final LatLng startLatLng = proj.fromScreenLocation(startPoint);
         final long duration = 500;
        final Interpolator interpolator = new LinearInterpolator();
        handler.post(new Runnable() {
            @Override
            public void run() {
                long elapsed = SystemClock.uptimeMillis() - start;
                float t = interpolator.getInterpolation((float) elapsed
                        / duration);
                double lng = t * toPosition.longitude + (1 - t)
                        * startLatLng.longitude;
                double lat = t * toPosition.latitude + (1 - t)
                        * startLatLng.latitude;
                marker.setPosition(new LatLng(lat, lng));
                if (t < 1.0) {
                    // Post again 16ms later.
                    handler.postDelayed(this, 16);
                } else {
                    if (hideMarker) {
                        marker.setVisible(false);
                    } else {
                        marker.setVisible(true);
                    }
                }
            }
        });
    }
}

где fragment_map_drag_listener.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1">

        <fragment
            android:id="@+id/map_container"
            android:name="com.google.android.gms.maps.SupportMapFragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

        <ImageView
            android:id="@+id/iv_center_overlay"
            android:layout_width="25dp"
            android:layout_height="25dp"
            android:visibility="gone"
            android:layout_centerInParent="true"
            android:src="@drawable/start_blue" />
    </RelativeLayout>


    <TextView
        android:id="@+id/tv_location_name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="4dp"
        android:text="Location Name" />
</LinearLayout>

где MapDragListenerActivity

public class MapDragListenerActivity extends AppCompatActivity {

    private Context mContext;
    private static final String TAG = MapDragListenerFragment.class.getSimpleName();
    private MapDragListenerFragment mapDragListenerFragment;

    private Button selectPlaceBtn;
    public static final int PLACE_AUTOCOMPLETE_REQUEST_CODE = 1219;

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

        mContext = MapDragListenerActivity.this;

        mapDragListenerFragment = new MapDragListenerFragment();
        getSupportFragmentManager().beginTransaction()
                .replace(R.id.frame_container,//where frame_container is a FrameLayout
                        mapDragListenerFragment,
                        MapyFragment.class.getSimpleName()).commit();


        selectPlaceBtn = (Button) findViewById(R.id.btn_select_place);

        selectPlaceBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                try {
                    Intent intent = new PlaceAutocomplete.IntentBuilder(
                            PlaceAutocomplete.MODE_FULLSCREEN).build(MapDragListenerActivity.this);
                    startActivityForResult(intent, PLACE_AUTOCOMPLETE_REQUEST_CODE);
                } catch (GooglePlayServicesRepairableException e) {
                    e.printStackTrace();
                } catch (GooglePlayServicesNotAvailableException e) {
                    e.printStackTrace();
                }
            }
        });
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if(requestCode == PLACE_AUTOCOMPLETE_REQUEST_CODE){
            if (resultCode == RESULT_OK) {
                Place place = PlaceAutocomplete.getPlace(mContext, data);
                if(mapDragListenerFragment != null && mapDragListenerFragment.isVisible())
                    mapDragListenerFragment.updateMarkerAtPosition(
                            place.getLatLng() ,place.getName().toString());

                Log.i(TAG, "Place:" + place.toString());
            } else if (resultCode == PlaceAutocomplete.RESULT_ERROR) {
                Status status = PlaceAutocomplete.getStatus(mContext, data);
                Log.i(TAG, status.getStatusMessage());
            } else if (requestCode == RESULT_CANCELED) {

            }
        }
    }
}

activity_map_drag_listener.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <Button
        android:id="@+id/btn_select_place"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Select Place" />

    <FrameLayout
        android:id="@+id/frame_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>

Ответ 7

@Override
public boolean onTouchEvent(MotionEvent event, MapView mapView){

    if(event.getAction() == MotionEvent.ACTION_MOVE)
        return true;

    return false;
}

Ответ 8

Я думаю, что событие onclick на карте: map.setOnMapClick... Но перетаскивание события: map.onCameraChangeListener, потому что я вызываю log.e в обеих этих функциях, и он отображается как onClick и onDrag. Поэтому просто используйте их для вас.

Ответ 9

Усовершенствованное решение с внутренним классом Handler в Xamarin Android, основанное на ответе Tobus:

public void OnMapReady(GoogleMap googleMap)
{
        _googleMap = googleMap;

        if (_googleMap != null)
        {
            _cameraPositionHandler = new CameraPositionlHandler(_googleMap);

            _googleMap.CameraChange += OnCameraChanged; 

        }
}

void OnCameraChanged (object sender, GoogleMap.CameraChangeEventArgs e)
{   
    _cameraPositionHandler.RemoveMessages(MESSAGE_ID_SAVE_CAMERA_POSITION);
    _cameraPositionHandler.RemoveMessages(MESSAGE_ID_READ_CAMERA_POSITION);                 
    _cameraPositionHandler.SendEmptyMessageDelayed(MESSAGE_ID_SAVE_CAMERA_POSITION, 300);
    _cameraPositionHandler.SendEmptyMessageDelayed(MESSAGE_ID_READ_CAMERA_POSITION, 600);

}

Со следующим внутренним классом:

    private class CameraPositionlHandler :  Handler 
    {
        private CameraPosition _lastCameraPosition;
        private GoogleMap _googleMap;

        public CameraPositionlHandler (GoogleMap googleMap)
        {
            _googleMap = googleMap;
        }

        public override void HandleMessage(Message msg) 
        {
            if (_googleMap != null) 
            {
                if (msg.What == MESSAGE_ID_SAVE_CAMERA_POSITION) {
                    _lastCameraPosition = _googleMap.CameraPosition;
                } else if (msg.What == MESSAGE_ID_READ_CAMERA_POSITION) {
                    if (_lastCameraPosition.Equals(_googleMap.CameraPosition)) {
                        Console.WriteLine("Camera position stable");
                        //do what you want
                    }
                }
            }
        }
    }

Ответ 11

Самый простой способ - использовать метод setOnCameraIdleListener для обработки состояния конечного состояния прослушивания касания вашего фрагмента карты. см. пример ниже:

mMap.setOnCameraMoveStartedListener(new GoogleMap.OnCameraMoveStartedListener() {
    @Override
    public void onCameraMoveStarted(int i) {
        mapPin.startAnimation(animZoomOut);
    }
});

mMap.setOnCameraIdleListener(new GoogleMap.OnCameraIdleListener() {
    @Override
    public void onCameraIdle() {
        mapPin.startAnimation(animZoomIn);
    }
});