MKMapView масштабирование для соответствия аннотациям при блокировке центра

Я пытаюсь масштабировать, чтобы соответствовать аннотациям на карте, блокируя центр и предоставляя некоторые вставки.

- (void)fitAnnotations:(NSArray *)annotations edgeInsets:(UIEdgeInsets)insets
{
    CLLocationCoordinate2D originalCenter = self.centerCoordinate;
    MKMapRect mapRect = MKMapRectNull;

    for (id<MKAnnotation> annotation in annotations) {
        MKMapPoint p = MKMapPointForCoordinate([annotation coordinate]);
        mapRect = MKMapRectUnion(mapRect, MKMapRectMake(p.x, p.y, 0, 0));
    }

    mapRect = [self mapRectThatFits:mapRect edgePadding:insets];
    MKCoordinateRegion mapRegion = MKCoordinateRegionForMapRect(mapRect);

    // we now try to go back to the original center, while increasing the span by neccessary amount
    MKCoordinateSpan centeringDelta = MKCoordinateSpanMake(fabs(mapRegion.center.latitude - originalCenter.latitude), fabs(mapRegion.center.longitude - originalCenter.longitude));
    mapRegion.center = originalCenter;
    mapRegion.span.latitudeDelta += centeringDelta.latitudeDelta * 2.0;
    mapRegion.span.longitudeDelta += centeringDelta.longitudeDelta * 2.0;
    mapRegion = [self regionThatFits:mapRegion];
    [self setRegion:mapRegion animated:YES];
}

Первая часть кода работает так, как ожидалось: она масштабируется до соответствия вставкам. Однако он перемещает центр.

Я пытаюсь снова настроить центр после этого, но он терпит неудачу. Я не уверен, правильна ли моя математика по переориентации.

Ответ 1

Попробуйте что-то подобное, когда вы используете свой расчетный mapRect для создания нового региона с вашим исходным центром через метод MKCoordinateRegionMake

MKCoordinateRegion mapRegion = MKCoordinateRegionForMapRect(mapRect);
mapRegion = MKCoordinateRegionMake(originalCenter, mapRegion.span);
mapView.region = mapRegion;

Ответ 2

Первая часть вашего кода, которая вычисляет ограничивающий прямоугольник карты, который подходит для аннотаций, находится в порядке.

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

Основная проблема, по-моему, состоит в том, что код в вопросе заключается в настройке диапазона как для повторного центрирования региона, так и для учета вставки после вызова mapRectThatFits: (который сам уже будет давать слегка измененную версию вы действительно запросили).

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

Попробуйте следующее:

- (void)fitAnnotations:(NSArray *)annotations edgeInsets:(UIEdgeInsets)insets
{
    MKMapPoint centerMapPoint = MKMapPointForCoordinate(originalCenter);

    //--- First create minimal bounding map rect to tightly fit annotations...
    MKMapRect minimalMapRect = MKMapRectNull;

    for (id<MKAnnotation> annotation in annotations) {
        MKMapPoint annMapPoint = MKMapPointForCoordinate(annotation.coordinate);
        minimalMapRect = MKMapRectUnion(minimalMapRect, MKMapRectMake(annMapPoint.x, annMapPoint.y, 0, 0));
    }


    //--- Now create adjusted map rect so center coordinate is in the center...

    //distance of desired center from minimal left edge...
    double centerXOffset = centerMapPoint.x - minimalMapRect.origin.x;

    //raw amount width needs to be adjusted to get center in center...
    //negative/positive indicates whether center is in left/right half
    double widthOffset = 2.0 * centerXOffset - minimalMapRect.size.width;

    //add absolute value of raw width offset to minimal width...
    double adjustedWidth = minimalMapRect.size.width + fabs(widthOffset);

    //distance of desired center from minimal top edge...
    double centerYOffset = centerMapPoint.y - minimalMapRect.origin.y;

    //raw amount height needs to be adjusted to get center in center...
    //negative/positive indicates whether center is in top/bottom half
    double heightOffset = 2.0 * centerYOffset - minimalMapRect.size.height;

    //add absolute value of raw height offset to minimal height...
    double adjustedHeight = minimalMapRect.size.height + fabs(heightOffset);

    //adjust origin if necessary (if center is in top/left half)...
    MKMapPoint adjustedOrigin = minimalMapRect.origin;
    if ((centerXOffset / minimalMapRect.size.width) < 0.5)
    {
        adjustedOrigin.x = adjustedOrigin.x + widthOffset;
    }
    if ((centerYOffset / minimalMapRect.size.height) < 0.5)
    {
        adjustedOrigin.y = adjustedOrigin.y + heightOffset;
    }

    //create adjusted MKMapRect...
    MKMapRect adjustedMapRect = MKMapRectMake(adjustedOrigin.x, adjustedOrigin.y, adjustedWidth, adjustedHeight);


    //--- Apply the adjusted map rect with insets to map view...
    [mapView setVisibleMapRect:adjustedMapRect edgePadding:insets animated:YES];
}

Ответ 3

Попробуйте это.

MKMapPoint center = MKMapPointForCoordinate(self.mapView.centerCoordinate);

double maxX = 0;
double maxY = 0;
for (MKPointAnnotation *a in self.mapView.annotations)
{
    MKMapPoint p = MKMapPointForCoordinate(a.coordinate);
    double deltaX = fabs(center.x - p.x);
    double deltaY = fabs(center.y - p.y);
    maxX = MAX(maxX, deltaX);
    maxY = MAX(maxY, deltaY);
}


MKMapRect rect = MKMapRectMake(center.x - maxX, center.y - maxY, maxX * 2, maxY * 2);
rect = [self.mapView mapRectThatFits:rect edgePadding:UIEdgeInsetsMake(20, 20, 20, 20)];

[self.mapView setVisibleMapRect:rect animated:1];

Ответ 4

@moby Я думаю о другом подходе. Как насчет того, чтобы разместить местоположение центра карты, как вы уже делали. Теперь вычислите расстояние до каждой аннотации от этой центральной координаты, пока не найдете самую длинную аннотацию (например, "requiredDistance" ). Получите новый прямоугольник карты со всеми вашими аннотациями, нанесенными на один и тот же центр, используя следующий код:

    MKCircle *circleLine = [MKCircle circleWithCenterCoordinate:self.centerCoordinate radius:requiredDistance];
    [self.mapView setVisibleMapRect:circleLine.boundingMapRect];

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