在MKMapView上添加带模糊效果的圆形

13

我正在尝试在地图上的覆盖层上添加模糊效果。实际上,我需要在覆盖了地图上的圆形区域上添加模糊效果,我使用的方法并不重要。

我有一个继承自MKCircleRenderer的类,我想在它覆盖的地图上添加模糊效果。

我试着使用-fillPath:inContext:方法,但是我的对Core Graphics和Core Image的无知让我一无所获,我真的非常迷失在这个问题上。

我的尝试是使用CIFilter,为此我需要一个CIImage,我试图从上下文中创建它。但是我找不到任何方法来创建一个CGBitmapContextCGImage或者其他任何从上下文中创建的类。我尝试的任何方法都会导致NULL,并没有更多关于原因的详细信息。我记不清我尝试了什么,所以对此我感到很抱歉。

我的类目前只实现了一个没有什么作用的方法:

- (instancetype)initWithOverlay:(id<MKOverlay>)overlay {
    if (self = [super initWithOverlay:overlay]) {
        self.strokeColor = [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:1];
        self.fillColor = [UIColor colorWithRed:0.4 green:0.2 blue:0.2 alpha:0.1];
        self.lineWidth = 1;
    }
    return self;
}

另一种方法是使用自定义的MKAnnotation,并使用UIVisualEffectView在视图上添加模糊效果。这种方法的难点在于缩放时增加/减小大小。

这应该适用于iOS 8及以上版本。

编辑

在这种情况下,圆形内部背后的地图应该被模糊处理。


你能提供一下你想要实现的效果的截图吗?是要除了一个特定的圆以外,将地图模糊掉吗?还是只需要将一个圆模糊掉?为什么这与缩放有关呢? - luk2302
最好能展示一张你需要的截图。 - Nikita Zernov
模糊圆形。我想要一个被模糊圆形覆盖的区域。该区域应该有四分之一英里的半径,因此如果有人放大/缩小它,它必须改变大小。我很快就会添加一张图片。 - Matías Marquez
2个回答

2

我最终使用了一个覆盖层上的 UIVisualEffectView。关键在于使用 CADisplayLink 来保持视图的位置。

以下是一些能够完成任务的代码示例(它忽略了一些应该考虑的东西,例如删除链接,跟踪在 viewDidAppear 中完成的工作需要与 viewWillDissapear 或其他内容成对出现,我认为可以使用 viewDidLoad,但测试时使用了这种方式)。

#import "ViewController.h"
#import <MapKit/MapKit.h>
#import <QuartzCore/QuartzCore.h>

@interface ViewController () {
    IBOutlet MKMapView *map;
    UIView *ov;
    MKCircle *c;
    UIVisualEffectView *ev;
}

@end

@implementation ViewController

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];

    CLLocationCoordinate2D center = CLLocationCoordinate2DMake(40.7828647,-73.9675438);
    c = [MKCircle circleWithCenterCoordinate:center radius:1000];
    [map addOverlay:c];
    MKCoordinateSpan span = MKCoordinateSpanMake(0.07, 0.07);
    MKCoordinateRegion region = MKCoordinateRegionMake(center, span);
    region = [map regionThatFits:region];
    [map setRegion:region animated:YES];

    ov = [[UIView alloc] init];
    ov.translatesAutoresizingMaskIntoConstraints = NO;
    ov.backgroundColor = [UIColor clearColor];
    ov.clipsToBounds = YES;
    ov.layer.borderWidth = 1;
    ov.layer.borderColor = [UIColor blackColor].CGColor;
    [map addSubview:ov];

    UIBlurEffect *blur = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
    ev = [[UIVisualEffectView alloc] initWithEffect:blur];
    [ov addSubview:ev];

    CADisplayLink *link = [CADisplayLink displayLinkWithTarget:self selector:@selector(update:)];
    [link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
}

- (void)update:(CADisplayLink *)link {
    ov.frame = [map convertRegion:MKCoordinateRegionForMapRect(c.boundingMapRect) toRectToView:map];
    ov.layer.cornerRadius = ov.frame.size.height / 2;
    ev.frame = CGRectMake(0, 0, ov.frame.size.width, ov.frame.size.height);
}

@end

编辑:屏幕截图


2
有两种方法可以做到这一点。
其中一种很简单,你只需使用图像。
你可能会发现以下图片有用:

enter image description here enter image description here enter image description here enter image description here enter image description here

并且在viewForAnnotation:方法中使用它们的代码

- (MKAnnotationView *) mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>) annotation
{   
    // ... get the annotation delegate and allocate the MKAnnotationView (annView)
        if ([annotationDelegate.type localizedCaseInsensitiveCompare:@"NeedsBluePin"] == NSOrderedSame)
        {
            UIImage * image = [UIImage imageNamed:@"blue_pin.png"];
            UIImageView *imageView = [[[UIImageView alloc] initWithImage:image] autorelease];
            [annView addSubview:imageView];
        }
}

其他方法可以通过编程来实现[自己画圆]。
这段代码可以帮助你。
import UIKit
import AddressBook
import AddressBookUI
import MapKit
import CoreLocation
import MessageUI
import Social

class ViewController: UIViewController, ABPeoplePickerNavigationControllerDelegate, MFMailComposeViewControllerDelegate, MKMapViewDelegate {

    @IBOutlet weak var name: UILabel!
    @IBOutlet weak var email: UILabel!
    @IBOutlet weak var photo: UIImageView!
    @IBOutlet weak var map: MKMapView!

    let locMan:CLLocationManager=CLLocationManager()

    // Blurring Code
    @IBOutlet weak var labelBackground: UIView!
    var backgroundBlur: UIVisualEffectView!


    @IBAction func newBFF(sender: AnyObject) {
        let picker: ABPeoplePickerNavigationController =
            ABPeoplePickerNavigationController()
        picker.peoplePickerDelegate = self
        presentViewController(picker, animated: true, completion: nil)
    }

    @IBAction func sendEmail(sender: AnyObject) {
        var emailAddresses:[String]=[self.email.text!]
        var mailComposer:MFMailComposeViewController =
            MFMailComposeViewController()
        mailComposer.mailComposeDelegate=self;
        mailComposer.setToRecipients(emailAddresses)

        presentViewController(mailComposer, animated: true, completion: nil)
    }

    func mailComposeController(controller: MFMailComposeViewController!,
        didFinishWithResult result: MFMailComposeResult, error: NSError!) {
        dismissViewControllerAnimated(true, completion: nil)
    }

    func peoplePickerNavigationController(peoplePicker: ABPeoplePickerNavigationController!, didSelectPerson person: ABRecord!) {

        let friendName:String = ABRecordCopyValue(person, kABPersonFirstNameProperty).takeRetainedValue() as String as String
        name.text=friendName

        let friendAddressSet:ABMultiValueRef = ABRecordCopyValue(person, kABPersonAddressProperty).takeRetainedValue()

        if ABMultiValueGetCount(friendAddressSet)>0 {
            let friendFirstAddress: Dictionary = ABMultiValueCopyValueAtIndex(friendAddressSet, 0).takeRetainedValue() as NSDictionary
            showAddress(friendFirstAddress)
        }

        let friendEmailAddresses:ABMultiValueRef = ABRecordCopyValue(person, kABPersonEmailProperty).takeRetainedValue()

        if ABMultiValueGetCount(friendEmailAddresses)>0 {
            let friendEmail: String = ABMultiValueCopyValueAtIndex(friendEmailAddresses, 0).takeRetainedValue() as String
            email.text=friendEmail
        }

        if ABPersonHasImageData(person) {
            photo.image = UIImage(data: ABPersonCopyImageData(person).takeRetainedValue())
        }
    }

    func showAddress(fullAddress:NSDictionary) {
        let geocoder: CLGeocoder = CLGeocoder()
        geocoder.geocodeAddressDictionary(fullAddress, completionHandler:
            {(placemarks: [AnyObject]!, error: NSError!) -> Void in
                let friendPlacemark:CLPlacemark = placemarks[0] as CLPlacemark
                let mapRegion:MKCoordinateRegion =
                    MKCoordinateRegion(center: friendPlacemark.location.coordinate,
                        span: MKCoordinateSpanMake(0.2, 0.2))
                self.map.setRegion(mapRegion, animated: true)
                let mapPlacemark: MKPlacemark = MKPlacemark(placemark: friendPlacemark)
                self.map.addAnnotation(mapPlacemark)
        })
    }

    func mapView(aMapView: MKMapView!,
        viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView! {
            let pinDrop:MKPinAnnotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: "myspot")
            pinDrop.animatesDrop=true
            pinDrop.canShowCallout=true
            pinDrop.pinColor=MKPinAnnotationColor.Purple
            return pinDrop
    }

    @IBAction func sendTweet(sender: AnyObject) {
        let geocoder: CLGeocoder = CLGeocoder()
        geocoder.reverseGeocodeLocation(map.userLocation.location, completionHandler:
            {(placemarks: [AnyObject]!, error: NSError!) -> Void in
                let myPlacemark:CLPlacemark = placemarks[0] as CLPlacemark
                let tweetText:String =
                    "Hello all - I'm currently in \(myPlacemark.locality)!"

                let tweetComposer: SLComposeViewController =
                    SLComposeViewController(forServiceType: SLServiceTypeTwitter)

                if SLComposeViewController.isAvailableForServiceType(SLServiceTypeTwitter) {
                    tweetComposer.setInitialText(tweetText)
                    self.presentViewController(tweetComposer, animated: true, completion: nil)
                }
        })
    }


    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        //let locMan:CLLocationManager=CLLocationManager()
        locMan.requestWhenInUseAuthorization()

        let blur: UIBlurEffect = UIBlurEffect(style: UIBlurEffectStyle.Light)
        backgroundBlur = UIVisualEffectView (effect: blur)
        backgroundBlur.frame = labelBackground.frame
        view.insertSubview(backgroundBlur, belowSubview: labelBackground)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    override func preferredStatusBarStyle() -> UIStatusBarStyle {
        return UIStatusBarStyle.LightContent
    }


}

1
也许我表达有误,但在编辑中是正确的。我需要模糊圆圈后面的地图而不是一个漂浮在地图上的圆圈 :/ 无论如何还是谢谢。 - Matías Marquez
1
据我所知,注释视图也会忽略缩放。如果我放大或缩小视图,它将在屏幕上显示相同的大小,但与地图上实际显示的内容无关。 - Matías Marquez

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接