Как центрировать камеру так, чтобы маркер находился в нижней части экрана? (Google map api V2 Android)

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

@Override

public boolean onMarkerClick(final Marker marker) {


    // Google sample code comment : We return false to indicate that we have not

    // consumed the event and that we wish
    // for the default behavior to occur (which is for the camera to move
    // such that the
    // marker is centered and for the marker's info window to open, if it
    // has one).

    marker.showInfoWindow();

            CameraUpdate center=
                CameraUpdateFactory.newLatLng(new LatLng(XXXX,
                                                         XXXX));
            mMap.moveCamera(center);//my question is how to get this center

            // return false;
    return true;
}

Edit:

проблема решена с помощью шагов принятого ответа, коды ниже:

@Override

    public boolean onMarkerClick(final Marker marker) {

                //get the map container height
        LinearLayout mapContainer = (LinearLayout) findViewById(R.id.map_container);
        container_height = mapContainer.getHeight();

        Projection projection = mMap.getProjection();

        LatLng markerLatLng = new LatLng(marker.getPosition().latitude,
                marker.getPosition().longitude);
        Point markerScreenPosition = projection.toScreenLocation(markerLatLng);
        Point pointHalfScreenAbove = new Point(markerScreenPosition.x,
                markerScreenPosition.y - (container_height / 2));

        LatLng aboveMarkerLatLng = projection
                .fromScreenLocation(pointHalfScreenAbove);

        marker.showInfoWindow();
        CameraUpdate center = CameraUpdateFactory.newLatLng(aboveMarkerLatLng);
        mMap.moveCamera(center);
        return true;



    }

Спасибо за помощь ^ ^

9 ответов


я мог бы отредактировать этот ответ позже, чтобы предоставить некоторый код, но я думаю, что это может сработать:

  1. Get LatLng (LatLng M) выбранного маркера.
  2. преобразование LatLng M до Point (Точка М) С помощью Projection.toScreenLocation(LatLng) метод. Это дает вам местоположение маркера на экране устройства (в пикселях).
  3. вычислить местоположение точки (Новая Точка), что выше Точка М на половину высоты карты.
  4. преобразование Новая Точка на LatLng и центрировать карту на нем.

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

    // googleMap is a GoogleMap object
    // view is a View object containing the inflated map
    // marker is a Marker object
    Projection projection = googleMap.getProjection();
    LatLng markerPosition = marker.getPosition();
    Point markerPoint = projection.toScreenLocation(markerPosition);
    Point targetPoint = new Point(markerPoint.x, markerPoint.y - view.getHeight() / 2);
    LatLng targetPosition = projection.fromScreenLocation(targetPoint);
    googleMap.animateCamera(CameraUpdateFactory.newLatLng(targetPosition), 1000, null);

да, используйте класс проекции. Более конкретно:

получить проекцию карты:

 Projection projection = map.getProjection();

получить местоположение вашего маркера:

 LatLng markerLocation = marker.getPosition();

передать местоположение проекции.toScreenLocation() метод:

 Point screenPosition = projection.toScreenLocation(markerLocation);

как это вы можете переместить маркер относительно центра или вокруг экрана

Point mappoint = googleMap.getProjection().toScreenLocation(new LatLng(latitude, longitude));
        mappoint.set(mappoint.x, mappoint.y-30);
        googleMap.animateCamera(CameraUpdateFactory.newLatLng(googleMap.getProjection().fromScreenLocation(mappoint)));

Я предпочитаю ответ Ларри Маккензи, который не зависит от проекции экрана (т. е. mProjection.toScreenLocation ()), я предполагаю, что разрешение проекции будет плохим, когда уровень масштабирования карты низкий, это заставило меня иногда не получать точную позицию. Таким образом, расчет на основе спецификации карты google, безусловно, решит проблему.

Ниже приведен пример кода перемещения маркера до 30% от размера экрана снизу.

zoom_lvl = mMap.getCameraPosition().zoom;
double dpPerdegree = 256.0*Math.pow(2, zoom_lvl)/170.0;
double screen_height = (double) mapContainer.getHeight();
double screen_height_30p = 30.0*screen_height/100.0;
double degree_30p = screen_height_30p/dpPerdegree;      
LatLng centerlatlng = new LatLng( latlng.latitude + degree_30p, latlng.longitude );         
mMap.animateCamera( CameraUpdateFactory.newLatLngZoom( centerlatlng, 15 ), 1000, null);

У меня была такая же проблема, я попробовал следующее отлично рабочее решение

mMap.setOnMarkerClickListener(new OnMarkerClickListener() 
        {
            @Override
            public boolean onMarkerClick(Marker marker)
            {
                int yMatrix = 200, xMatrix =40;

                DisplayMetrics metrics1 = new DisplayMetrics();
                getWindowManager().getDefaultDisplay().getMetrics(metrics1);
                switch(metrics1.densityDpi)
                {
                case DisplayMetrics.DENSITY_LOW:
                    yMatrix = 80;
                    xMatrix = 20;
                    break;
                case DisplayMetrics.DENSITY_MEDIUM:
                    yMatrix = 100;
                    xMatrix = 25;
                    break;
                case DisplayMetrics.DENSITY_HIGH:
                    yMatrix = 150;
                    xMatrix = 30;
                    break;
                case DisplayMetrics.DENSITY_XHIGH:
                    yMatrix = 200;
                    xMatrix = 40;
                    break;
                case DisplayMetrics.DENSITY_XXHIGH:
                    yMatrix = 200;
                    xMatrix = 50;
                    break;
                }

                Projection projection = mMap.getProjection();
                LatLng latLng = marker.getPosition();
                Point point = projection.toScreenLocation(latLng);
                Point point2 = new Point(point.x+xMatrix,point.y-yMatrix);

                LatLng point3 = projection.fromScreenLocation(point2);
                CameraUpdate zoom1 = CameraUpdateFactory.newLatLng(point3);
                mMap.animateCamera(zoom1);
                marker.showInfoWindow();
                return true;
            }
        });

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

double center = mMap.getCameraPosition().target.latitude;
double southMap = mMap.getProjection().getVisibleRegion().latLngBounds.southwest.latitude;

double diff = (center - southMap);

double newLat = marker.getPosition().latitude + diff;

CameraUpdate centerCam = CameraUpdateFactory.newLatLng(new LatLng(newLat, marker.getPosition().longitude));

mMap.animateCamera(centerCam);

Я сделал небольшое исследование, и в соответствии с документацией карта квадратная и при нулевом уровне масштабирования ширина и высота 256dp и + / - 85 градусов N / S. ширина карты увеличивается с уровнем масштабирования, так что ширина и высота = 256 * 2N dp. Где N-масштаб. Таким образом, теоретически вы можете определить новое местоположение, получив высоту карты и разделив ее на 170 градусов, чтобы получить dp на градус. Затем получите высоту экрана (или высоту mapview) в dp, разделив его на два и преобразуйте половину вида размер в градусах широты. Затем установите новую точку Камеры на много градусов южной широты. Я могу добавить код, если вам это нужно, но я сейчас на телефоне.


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

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

@Override
public boolean onMarkerClick(Marker marker) {
    mIsMarkerClick = true;
    mHandler.removeCallbacks(mUpdateTimeTask);
    mLoadTask.cancel(true);
    getActivity().setProgressBarIndeterminateVisibility(false);
    marker.showInfoWindow();
    Projection projection = getMap().getProjection();
    Point marketCenter = projection.toScreenLocation(marker.getPosition());
    float tiltFactor = (90 - getMap().getCameraPosition().tilt) / 90;
    marketCenter.y -= mInfoWindowAdapter.getInfoWindowHeight() / 2 * tiltFactor;
    LatLng fixLatLng = projection.fromScreenLocation(marketCenter);

    mMap.animateCamera(CameraUpdateFactory.newLatLng(fixLatLng), null);

    return true;
}

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

public int getInfoWindowHeight(){
    if (mLastInfoWindoView != null){
        return mLastInfoWindoView.getMeasuredHeight();
    }
    return 0;
}

любой, кто все еще ищет, чтобы центрировать камеру в соответствии с координатами местоположения

CameraPosition cameraPosition = new CameraPosition.Builder().target(new LatLng(Lat, Lon))
        .zoom(15) 
        .bearing(0)
        .tilt(45)
        .build();
    map.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));

кредиты


после некоторого опыта я реализовал решение, которое отлично подходит для меня.

DisplayMetrics metrics = new DisplayMetrics();
context.getWindowManager().getDefaultDisplay().getMetrics(metrics);

Point targetPoint = new Point(metrics.widthPixels / 2, metrics.heightPixels - metrics.heightPixels / 9);
LatLng targetLatlng = map.getProjection().fromScreenLocation(targetPoint);
double fromCenterToTarget = SphericalUtil.computeDistanceBetween(map.getCameraPosition().target, targetLatlng);

LatLng center = SphericalUtil.computeOffset(new LatLng(location.latitude, location.longitude), fromCenterToTarget/1.2, location.bearing);
CameraUpdate camera = CameraUpdateFactory.newLatLng(center);
map.animateCamera(camera, 1000, null);

здесь. Во-первых, мы выбираем физическую точку на экране, куда должен быть перемещен маркер. Затем преобразуйте его в LatLng. Следующий шаг-вычислить расстояние от текущей позиции маркера (в центре) до цели. Наконец, мы перемещаем центр карты прямо от маркера на расчетное расстояние.