在 MKMapView 上添加具有模糊效果的圆圈
Add circle with blur effect on a MKMapView
我正在尝试为地图上的叠加层添加模糊效果。我实际上需要在地图上的一个圆圈上的模糊效果,我用来获得它的方法并不那么重要。
我有一个从 MKCircleRenderer
延伸出来的 class,我想在它覆盖的地图上添加模糊效果。
我正在尝试使用 -fillPath:inContext:
方法,但我对 Core Graphics 和 Core Image 的无知让我无所适从,我真的很迷茫这个问题。
我尝试使用 CIFilter
,为此我需要一个 CIImage
,我试图从上下文中创建它。但是我找不到从上下文中创建 CGBitmapContext
、CGImage
或任何其他 class 的方法。我尝试过的任何方法都会导致 NULL,但没有关于原因的更多详细信息。我不记得我尝试过的所有内容,所以我很抱歉没有指出任何相关内容。
我的 class 目前实现了一种方法,但作用不大:
- (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
在视图上添加模糊效果。这种方法的困难部分是 increasing/decreasing 缩放时的大小。
这应该适用于 iOS 8+
编辑
在这种情况下,圆圈内侧后面的地图应该是模糊的
有两种方法可以做到这一点。
一个很简单,用Image就可以了。
您可能会发现以下图片有用:
以及在 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
}
}
所以我最终在叠加层上使用了 UIVisualEffectView
。诀窍在于使用 CADisplayLink
来保持视图的位置。
这里是一些完成这项工作的代码示例(它忽略了一些在应用程序上实际执行此操作时应该考虑的事情,例如删除 link,跟踪在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
编辑:截图
我正在尝试为地图上的叠加层添加模糊效果。我实际上需要在地图上的一个圆圈上的模糊效果,我用来获得它的方法并不那么重要。
我有一个从 MKCircleRenderer
延伸出来的 class,我想在它覆盖的地图上添加模糊效果。
我正在尝试使用 -fillPath:inContext:
方法,但我对 Core Graphics 和 Core Image 的无知让我无所适从,我真的很迷茫这个问题。
我尝试使用 CIFilter
,为此我需要一个 CIImage
,我试图从上下文中创建它。但是我找不到从上下文中创建 CGBitmapContext
、CGImage
或任何其他 class 的方法。我尝试过的任何方法都会导致 NULL,但没有关于原因的更多详细信息。我不记得我尝试过的所有内容,所以我很抱歉没有指出任何相关内容。
我的 class 目前实现了一种方法,但作用不大:
- (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
在视图上添加模糊效果。这种方法的困难部分是 increasing/decreasing 缩放时的大小。
这应该适用于 iOS 8+
编辑
在这种情况下,圆圈内侧后面的地图应该是模糊的
有两种方法可以做到这一点。
一个很简单,用Image就可以了。
您可能会发现以下图片有用:
以及在 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
}
}
所以我最终在叠加层上使用了 UIVisualEffectView
。诀窍在于使用 CADisplayLink
来保持视图的位置。
这里是一些完成这项工作的代码示例(它忽略了一些在应用程序上实际执行此操作时应该考虑的事情,例如删除 link,跟踪在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
编辑:截图