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

Фон

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

Проблема

Мне нужно сделать "камеру" на карте, сфокусироваться и иметь маркер на координате, но пусть все это будет в середине видимой части карты.

Что-то вроде этого:

введите описание изображения здесь

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

Вещь, я не могу найти правильный способ установить правильное значение для координаты Y самой карты (что означает широта).

Что я пробовал

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

    final float neededZoom = 6.5f;
    int bottomViewHeight = bottomView.getHeight();
    LatLng posToFocusOn = ...;
    final Point point = mMap.getProjection().toScreenLocation(posToFocusOn);
    final float curZoom = mMap.getCameraPosition().zoom;
    point.y += bottomViewHeight * curZoom / neededZoom;
    posToFocusOn = mMap.getProjection().fromScreenLocation(point);
    final CameraUpdate cameraPosition = CameraUpdateFactory.newCameraPosition(new Builder().target(posToFocusOn).zoom(neededZoom).build());

К сожалению, это фокусируется выше маркера.

Вопрос

Что случилось с тем, что я написал? Что я могу сделать, чтобы исправить это?

Ответ 1

ok, я нашел обходное решение, которое, я думаю, работает на всех устройствах (тестировалось по 3, каждое с различным разрешением и размером экрана):

Я измерил, сколько пикселей (а затем преобразовано в DP) изменение одной степени имеет на самом марке.

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

В моем случае это так (предположим, что масштаб составляет 6,5 фут):

    //measured as 223 pixels on Nexus 5, which has xxhdpi, so divide by 3
    final float oneDegreeInPixels = convertDpToPixels( 223.0f / 3.0f);
    final float mapViewCenter = mapViewHeight / 2.0f;
    final float bottomViewHeight = ...;
    final float posToFocusInPixelsFromTop = (mapViewHeight - bottomViewHeight) / 2.0f ;// can optionally add the height of the view on the top area
    final float deltaLatDegreesToMove = (mapViewCenter - posToFocusInPixelsFromTop) / oneDegreeInPixels;
    LatLng posToFocusOn = new LatLng(latitude - deltaLatDegreesToMove, longitude);
    final CameraUpdate cameraPosition = CameraUpdateFactory.newCameraPosition(new Builder().target(posToFocusOn).zoom(neededZoom).build());

И это сработало.

Интересно, можно ли его настроить для поддержки любого значения масштабирования.

Ответ 2

Ваш код почти прав, но он идет выше маркера, потому что вы принимаете во внимание bottomViewHeight при вычислении point.y вместо bottomViewHeight/2 (Когда размер вашего представления составляет 200 пикселей, вам нужно всего лишь вытеснить карту 100px для его повторного использования):

point.y += (bottomViewHeight / 2) * curZoom / neededZoom;

Update:

Это более общий подход. taht учитывает границы карт и вычисляет новые границы карт в соответствии с высотой вашего bottomView. Это независимое масштабирование.

public void recenter() {
    LatLngBounds mapBounds = mMap.getProjection().getVisibleRegion().latLngBounds;
    Point nothEastPoint = mMap.getProjection().toScreenLocation(mapBounds.northeast);
    Point souhWestPoint = mMap.getProjection().toScreenLocation(mapBounds.southwest);

    Point newNorthEast = new Point(nothEastPoint.x, nothEastPoint.y + bottomView.getHeight() / 2);
    Point newSouhWestPoint = new Point(souhWestPoint.x, souhWestPoint.y + bottomView.getHeight() / 2);

    LatLngBounds newBounds = LatLngBounds.builder()
            .include(mMap.getProjection().fromScreenLocation(newNorthEast))
            .include(mMap.getProjection().fromScreenLocation(newSouhWestPoint))
            .build();

    mMap.moveCamera(CameraUpdateFactory.newLatLngBounds(newBounds, 0));
}

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