【问题标题】:MapTypeStyle in MapKitMapKit 中的 MapTypeStyle
【发布时间】:2012-05-08 10:55:25
【问题描述】:

我想知道是否有任何方法可以配置我们的 MapKit 地图,就像我们在 Google Maps API 中使用 MapTypeStyle 对象一样。

如果我参考 Apple 文档,MKMapView 有一个 mapType 选项,它采用 MKMapType constant,但没有像 MapOptions 和 MapTypeStyleMapTypeStyler 这样的样式参数,这对于快速地图定制非常强大。

所以我的问题是:有没有办法用 MapKit 框架实现类似的东西,如果没有,最好的框架/库是什么?我在考虑MapBox 和类似的产品。

【问题讨论】:

  • 您可以通过更改私有类来修改 MKMapView 的颜色,但我很确定苹果不会允许这样做。如果你仍然对这个选项感兴趣,我会给你一个示例代码。
  • @Lee Armstrong 我添加了一个简短的示例代码

标签: ios google-maps ios5 map mapkit


【解决方案1】:

我的朋友,您有几个选择。您可以使用这些框架之一

http://cloudmade.com/products/iphone-sdk

https://github.com/route-me/route-me

或者你可以只使用 mapbox。他们的 api 看起来很不错。 或者,您提供自己的地图图块和覆盖 mapkit。 MKOverlayView 中的类似内容

- (void)drawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale inContext:(CGContextRef)context {

NSURL* fileURL = [(HeatMap*)self.overlay localUrlForStyle:@"alien" withMapRect:mapRect andZoomScale:zoomScale];
NSData *imageData = [NSData dataWithContentsOfURL:fileURL ];
if (imageData != nil) {
    UIImage* img = [UIImage imageNamed:@"aTileX.png"];
    // Perform the image render on the current UI context
    UIGraphicsPushContext(context);
    [img drawInRect:[self rectForMapRect:mapRect] blendMode:kCGBlendModeNormal alpha:1.0];
    UIGraphicsPopContext();
    }
}

如果你想要不受支持的“地形”模式,也可以看看这个 http://openradar.appspot.com/9621632

我实际上正在执行一个需要在地图上叠加图块的程序。 This example 非常有帮助。您需要查看 MKOverlay 和 MKOverlayView。我正在做的项目涉及使用gheat。我正在通过 NSURLConnection 访问磁贴并将它们存储在本地。我的实现的gist

【讨论】:

  • 在我的情况下,自定义图块选项似乎是最好的方法,因为我的地图被限制在一个城市范围内,缩放级别很少。我会挖掘这个,如果有任何方法可以在本地存储瓷砖,我可能会将此解决方案用于生产。您能否在答案中参考更多关于覆盖的信息/链接,以便我将此问题标记为已接受?非常感谢。
【解决方案2】:

无法使用 mapkit 本地自定义地图样式。您唯一的选择是选择混合应用方法,然后在页面本身中使用 html/javascript 自定义样式。

【讨论】:

  • 这是一个聪明而简单的解决方案,但在我的情况下不能使用。我投了赞成票,这样人们就可以看到这个可以满足其他人需求的解决方案。
【解决方案3】:

由于绘制瓷砖是在一个名为MKMapTileView 的私有类中进行的,因此您不能简单地编写一个类别。您必须为自定义绘图实现另一个类。该类的Methods将用于在运行时重载MKMapTileView的实现:

头文件:

@interface MyColorMap : NSObject
+ (void)overLoadMethods:(Class)destinationClass;
@end

实施:

#import "MyColorMap.h"
#import <objc/runtime.h>

@implementation MyColorMap

+ (void)overLoadMethods:(Class)destinationClass {
    // get the original method for drawing a tile
    Method originalDrawLayer = class_getInstanceMethod(destinationClass, @selector(drawLayer:inContext:));

    // get the method we will replace with the original implementation of 'drawLayer:inContext:' later
    Method backupDrawLayer = class_getInstanceMethod([self class], @selector(backupDrawLayer:inContext:));

    // get the method we will use to draw our own colors
    Method myDrawLayer = class_getInstanceMethod([self class], @selector(myDrawLayer:inContext:));

    // dito with the implementations
    IMP impOld = method_getImplementation(originalDrawLayer);
    IMP impNew = method_getImplementation(myDrawLayer);

    // replace the original 'drawLayer:inContext:' with our own implementation
    method_setImplementation(originalDrawLayer, impNew);

    // set the original 'drawLayer:inContext:' implementation to our stub-method, so wie can call it later on
    SEL selector = method_getName(backupDrawLayer);
    const char *types = method_getTypeEncoding(backupDrawLayer);
    class_addMethod(destinationClass, selector, impOld, types);
}


- (void)backupDrawLayer:(CALayer*)l inContext:(CGContextRef)c {
    // stub method, implementation will never be called. The only reason we implement this is so we can call the original method durring runtime
}

- (void)myDrawLayer:(CALayer*)l inContext:(CGContextRef)c {
    // set background to white so wie can use it for blendmode
    CGContextSetFillColorWithColor(c, [[UIColor whiteColor] CGColor]); 
    CGContextFillRect(c, CGContextGetClipBoundingBox(c));

    // set blendmode so the map will show as grayscale
    CGContextSetBlendMode(c, kCGBlendModeLuminosity);
    // kCGBlendModeExclusion for inverted colors etc.

    // calling the stub-method which will become the original method durring runtime
    [self backupDrawLayer:l inContext:c];

    // if you want more advanced manipulations you can alter the context after drawing:

//    int w = CGBitmapContextGetWidth(c);
//    int h = CGBitmapContextGetHeight(c);
//    
//    unsigned char* data = CGBitmapContextGetData(c);
//    if (data != NULL) {
//        int maxY = h;
//        for(int y = 0; y<maxY; y++) {
//            for(int x = 0; x<w; x++) {
//                
//                int offset = 4*((w*y)+x);
//                char r = data[offset];
//                char g = data[offset+1];
//                char b = data[offset+2]; 
//                char a = data[offset+3]; 
//                
//                // do what ever you want with the pixels
//                
//                data[offset] = r;
//                data[offset+1] = g; 
//                data[offset+2] = b;
//                data[offset+3] = a;
//            }
//        }
//    }
}

现在你必须在使用MKMapView之前的某个时间点调用[MyColorMap overLoadMethods:NSClassFromString(@"MKMapTileView")]

【讨论】:

  • 对于一个如此简单的需求,这似乎是一个深度破解 :) 我可能会使用覆盖(请参阅@jb1a1 答案),因为我看不到使用您的解决方案的好处。仍然是一件好事。感谢分享这个样本。希望 MapKit 快点升级,让我们用 JS 的方式自定义地图。
  • 这似乎不适用于 iOS 6 的 MKMapView 控件。这个版本可能不使用“MKMapTileView”吗?
  • 在 iOS 6 中地图被完全重构。大多数新的渲染都使用了 openGL,这个 hack 不再起作用了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-14
  • 2014-10-01
相关资源
最近更新 更多