yandex / mapkit-android-demo

MapKit Android demo
Other
121 stars 59 forks source link

UserLocationLayer перепрыгивает на местоположение пользователя #63

Closed alinaSib closed 5 years ago

alinaSib commented 5 years ago

Мне нужно показать местоположение пользователя на карте и сделать в эту точку зум при открытии карты и при нажатии кнопки. Делаю userLocationLayer.setEnabled(true). Но, если потом переместитья в другое место на карте через пару секунд камера опять перескакивает на местоположение пользователя. Какой метод позволяет от этого избавиться? В документации не нашла. (

EvgenBES commented 5 years ago

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

Я думаю сделать это вызовом в 1 раз ... То есть создам метом в onCreate , какой то типа initUserLocation(); в данном методе я сделаю данную реализацию и по итогу должно получиться что мы будем вызвать этот метод только при иницилизации активности.

EvgenBES commented 5 years ago

Сорри не сразу заметил что девушка) - реализовал(а). Пример из demo не передвигается на место расположения юзера когда смотрел его, возможно что-то забыл дописать или сделать, что бы он начал работать.

alinaSib commented 5 years ago
        //Show user location on map
        userLocationLayer = mapView.getMap().getUserLocationLayer();
        userLocationLayer.setEnabled(false);
        userLocationLayer.setHeadingEnabled(true);
        userLocationLayer.setObjectListener(this);

        moveCameraToPosition(userLocationLayer.cameraPosition().getTarget());

В onCreate это все и делается.

    public void moveCameraToPosition(@NonNull Point target) {
               mapView.getMap().move(
                        new CameraPosition(target, 15.0f, 0.0f, 0.0f),
                        new Animation(Animation.Type.SMOOTH, 2), null);
    }
EvgenBES commented 5 years ago

Нашёл проблему ... В настройках эмулятора (геолокации) не было разрешено моему приложение отслеживать моё место положение! После предоставления этих возможностей всё получилось и определилось!

Вот нашёл проект в котором нету такой проблемы как описано у тебя: https://github.com/MobileMirea/YandexMaps

у него нету такого метода moveCameraToPosition(.....)

за то он вызывает onObjectAdded(@NonNull UserLocationView userLocationView) .... и там всё это сделано ... Пока писал данный коммит карта не сдвинулась не на дюйм... Так что советую попробовать его реализацию ;)

alinaSib commented 5 years ago

Я использовала moveCameraToPosition для зума в эту точку. Но даже если я его закомментирую - зума не будет, а прыгать будет. Складывается впечатление, что виновата com.google.android.gms:play-services-location:16.0.0 и ее сервисы. Буду еще искать в чем проблема. По поводу onObjectAdded - там просто иконки для метки, ничего более. Спасибо.

ShtefanES commented 5 years ago

Подойдет вариант определения местоположения с использованием com.yandex.mapkit.location.LocationListener и com.yandex.mapkit.location.LocationManager или нужно использовать именно userLocationLayer?

ShtefanES commented 5 years ago

EvgenBES, не похоже, что проблема с эмулятором, запустил демо на Moto G5S android 8.1, проблема как у alinaSib.

ShtefanES commented 5 years ago

Вот пример рабочего кода(нет проверки разрешения для api>=23) для определения местоположения при старте и по клику fab:

public class MainActivity extends AppCompatActivity {

private static final String TAG = MainActivity.class.getSimpleName();
private static final double DESIRED_ACCURACY = 0;
private static final long MINIMAL_TIME = 0;
private static final double MINIMAL_DISTANCE = 50;
private static final boolean USE_IN_BACKGROUND = false;
public static final int COMFORTABLE_ZOOM_LEVEL = 18;
private final String MAPKIT_API_KEY = "your_api_key";
private MapView mapView;
private CoordinatorLayout rootCoordinatorLayout;
private LocationManager locationManager;
private LocationListener myLocationListener;
private Point myLocation;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    MapKitFactory.setApiKey(MAPKIT_API_KEY);
    MapKitFactory.initialize(this);
    setContentView(R.layout.activity_main);

    mapView = (MapView) findViewById(R.id.mapview);
    rootCoordinatorLayout = (CoordinatorLayout) findViewById(R.id.root_coordinator);

    locationManager = MapKitFactory.getInstance().createLocationManager();
    myLocationListener = new LocationListener() {
        @Override
        public void onLocationUpdated(Location location) {
            if (myLocation == null) {
                moveCamera(location.getPosition(), COMFORTABLE_ZOOM_LEVEL);
            }
            myLocation = location.getPosition();
            Log.w(TAG, "my location - " + myLocation.getLatitude() + "," + myLocation.getLongitude());
        }

        @Override
        public void onLocationStatusUpdated(LocationStatus locationStatus) {
            if (locationStatus == LocationStatus.NOT_AVAILABLE) {
                Snackbar.make(rootCoordinatorLayout, R.string.error_cant_get_my_location, Snackbar.LENGTH_LONG).show();
            }
        }
    };
}

@Override
protected void onStart() {
    super.onStart();
    MapKitFactory.getInstance().onStart();
    mapView.onStart();

    subscribeToLocationUpdate();
}

@Override
protected void onStop() {
    super.onStop();
    MapKitFactory.getInstance().onStop();
    locationManager.unsubscribe(myLocationListener);
    mapView.onStop();
}

public void onFabCurrentLocationClick(View view) {
    if (myLocation == null) {
        Snackbar.make(rootCoordinatorLayout, R.string.coordinates_are_not_yet_determinate, Snackbar.LENGTH_SHORT).show();
        return;
    }

    moveCamera(myLocation, COMFORTABLE_ZOOM_LEVEL);
}

private void subscribeToLocationUpdate() {
    if (locationManager != null && myLocationListener != null) {
        locationManager.subscribeForLocationUpdates(DESIRED_ACCURACY, MINIMAL_TIME, MINIMAL_DISTANCE, USE_IN_BACKGROUND, FilteringMode.OFF, myLocationListener);
    }
}

private void moveCamera(Point point, float zoom) {
    mapView.getMap().move(
            new CameraPosition(point, zoom, 0.0f, 0.0f),
            new Animation(Animation.Type.SMOOTH, 1),
            null);
}
}
EvgenBES commented 5 years ago

Я сделал так:

private void initUserLocation() { userLocationLayer = mapView.getMap().getUserLocationLayer(); userLocationLayer.setEnabled(true); userLocationLayer.setHeadingEnabled(true); userLocationLayer.setObjectListener(this); }

то есть без метода moveCameraToPosition, и метод zoom убрал тоже ... в onCreate mapView.getMap().move(new CameraPosition(new Point(0, 0), 12, 0, 0));

результат меня устроил.

iFr0z commented 5 years ago

https://github.com/iFr0z/FabUserLocation хоть и на kotlin, но не велика разница, т.к. методы используются те же.

ShtefanES commented 5 years ago

Пример iFr0z решает проблему, получается для того чтобы камера не перескакивала на текущее местоположение при перемещении по карте(как в демо), нужно в колбек onCameraPositionChanged добавить userLocationLayer.resetAnchor().

alinaSib commented 5 years ago

А у меня не получается с resetAnchor(). Также прыгает (

alinaSib commented 5 years ago

Ну и видимо мы все-таки разные задачи с iFr0z решаем. Мне не надо следить за пользователем после нажатии кнопки. А надо только один раз показать где он - при нажатии на кнопку. Поэтому мне помогло вообще не делать setAnchor() и плюс boolean флаг showLocation.
Что, кстати за Anchor mode, который этот метод включает не совсем понятно.

ShtefanES commented 5 years ago

Ваша активити или фрагмент должна реализовать интерфейс CameraListener. В колбеке: @Override public void onCameraPositionChanged(@NonNull Map map, @NonNull CameraPosition cameraPosition, @NonNull CameraUpdateSource cameraUpdateSource, boolean b) { if (b) { userLocationLayer.resetAnchor(); } } Так же стоит назначить слушателя: mapView.getMap().addCameraListener(this);

alinaSib commented 5 years ago

@ShtefanES Было бы замечательно вообще понять что делает setAnchor() и resetAnchor().

iFr0z commented 5 years ago

@alinaSib По порядку:

Было бы замечательно вообще понять что делает setAnchor() и resetAnchor().

userLocationLayer - это подключение слоя, который отобразит значок местоположения пользователя. setAnchor() - это якорь, который следит за значком местоположения пользователя. Также Вы можете задать ширину и длину участка (экрана), который будет участвовать (эдакий зум).
resetAnchor() - это для того, чтобы его снять, и не следить больше за значком местоположения пользователя.


Складывается впечатление, что виновата com.google.android.gms:play-services-location:16.0.0 и ее сервисы.

Эти сервисы являются основой :)


userLocationLayer.setObjectListener(this); // интерфейс UserLocationObjectListener

Добавляя данный слушатель, Вы имеете дело с такими методами, как onObjectAdded, onObjectRemoved, onObjectUpdated. Они действительно нужны для отображения значка местоположения пользователя и его состоянием, изменением.


Про триггер onCameraPositionChanged

alinaSib commented 5 years ago

@iFr0z Ну тогда все правильно. Мне действительно не нужен этот якорь. У меня нет цели следить за пользователем. Спасибо за подробный ответ!

iFr0z commented 5 years ago

@alinaSib Рад был помочь :)