Я столкнулся с этой самой проблемой на работе и создал что-то, что работает довольно хорошо, не устанавливая глобальное ограничение.
Используемые мной делегаты MapView:
- mapViewDidFinishRendering
- mapViewRegionDidChange
Исходное условие моего решения заключается в том, что, поскольку вид со спутника отображает область без данных, это всегда одно и то же. Это страшное изображение (http://imgur.com/cm4ou5g) Если мы можем с уверенностью полагаться на этот неудачный случай, мы можем использовать его в качестве ключа для определения того, что видит пользователь. После рендеринга карты я делаю снимок экрана с отображенными границами карты и определяю среднее значение RGB. Исходя из этого значения RGB, я предполагаю, что в рассматриваемой области нет данных. Если это так, я возвращаю карту обратно к последнему диапазону, который был правильно отображен.
Единственная глобальная проверка, которую я имею, - когда она начинает проверять карту, вы можете увеличивать или уменьшать этот параметр в зависимости от ваших потребностей. Ниже приведен необработанный код, который выполнит это и соберет пример проекта для вклада. Будем благодарны за любые оптимизации, которые вы можете предложить. Надеемся, что это поможет.
@property (assign, nonatomic) BOOL isMaxed;
@property (assign, nonatomic) MKCoordinateSpan lastDelta;
self.lastDelta = MKCoordinateSpanMake(0.006, 0.006);
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
if (mapView.mapType != MKMapTypeStandard && self.isMaxed) {
[self checkRegionWithDelta:self.lastDelta.longitudeDelta];
}
}
- (void)checkRegionWithDelta:(float)delta {
if (self.mapView.region.span.longitudeDelta < delta) {
MKCoordinateRegion region = self.mapView.region;
region.span = self.lastDelta;
[self.mapView setRegion:region animated:NO];
} else if (self.mapView.region.span.longitudeDelta > delta) {
self.isMaxed = NO;
}
}
- (void)mapViewDidFinishRenderingMap:(MKMapView *)mapView fullyRendered:(BOOL)fullyRendered {
if (mapView.mapType != MKMapTypeStandard && !self.isMaxed) {
[self checkToProcess:self.lastDelta.longitudeDelta];
}
}
- (void)checkToProcess:(float)delta {
if (self.mapView.region.span.longitudeDelta < delta) {
UIGraphicsBeginImageContext(self.mapView.bounds.size);
[self.mapView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *mapImage = UIGraphicsGetImageFromCurrentImageContext();
[self processImage:mapImage];
}
}
- (void)processImage:(UIImage *)image {
self.mapColor = [self averageColor:image];
const CGFloat* colors = CGColorGetComponents( self.mapColor.CGColor );
[self handleColorCorrection:colors[0]];
}
- (void)handleColorCorrection:(float)redColor {
if (redColor < 0.29) {
self.isMaxed = YES;
[self.mapView setRegion:MKCoordinateRegionMake(self.mapView.centerCoordinate, self.lastDelta) animated:YES];
} else {
self.lastDelta = self.mapView.region.span;
}
}
- (UIColor *)averageColor:(UIImage *)image {
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
unsigned char rgba[4];
CGContextRef context = CGBitmapContextCreate(rgba, 1, 1, 8, 4, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
CGContextDrawImage(context, CGRectMake(0, 0, 1, 1), image.CGImage);
CGColorSpaceRelease(colorSpace);
CGContextRelease(context);
if(rgba[3] > 0) {
CGFloat alpha = ((CGFloat)rgba[3])/255.0;
CGFloat multiplier = alpha/255.0;
return [UIColor colorWithRed:((CGFloat)rgba[0])*multiplier
green:((CGFloat)rgba[1])*multiplier
blue:((CGFloat)rgba[2])*multiplier
alpha:alpha];
}
else {
return [UIColor colorWithRed:((CGFloat)rgba[0])/255.0
green:((CGFloat)rgba[1])/255.0
blue:((CGFloat)rgba[2])/255.0
alpha:((CGFloat)rgba[3])/255.0];
}
}