MapKit not showing custom Annotation pin image on iOS9 - mkmapview

My code worked fine from iOS 7 to 8. With the update yesterday the custom images on my pins were replaced by the standard pin image.
Any suggestions?
My code:
extension ViewController: MKMapViewDelegate {
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView! {
if annotation is MKUserLocation {
return nil
}
let reuseId = String(stringInterpolationSegment: annotation.coordinate.longitude)
var pinView = mapView.dequeueReusableAnnotationViewWithIdentifier(reuseId) as? MKPinAnnotationView
if pinView == nil {
pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
pinView!.canShowCallout = true
pinView!.image = getRightImage(annotation.title!!)
}
let button = UIButton(type: UIButtonType.DetailDisclosure)
pinView?.rightCalloutAccessoryView = button
return pinView
}
}
The function to get the image returns a UIImage based on the name:
func getRightImage (shopName:String)-> UIImage{
var correctImage = UIImage()
switch shopName
{
case "Kaisers":
correctImage = UIImage(named: "Kaisers.jpg")!
default:
correctImage = UIImage(named: "sopiconsmall.png")!
}
return correctImage
}
No the map looks like this:

Instead of creating an MKPinAnnotationView, create a plain MKAnnotationView.
The MKPinAnnotationView subclass tends to ignore the image property since it's designed to show the standard red, green, purple pins only (via the pinColor property).
When you switch to MKAnnotationView, you'll have to comment out the animatesDrop line as well since that property is specific to MKPinAnnotationView.

Following code works perfectly on all iOS 6 to iOS 9 devices:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
// create a proper annotation view, be lazy and don't use the reuse identifier
MKAnnotationView *view = [[MKAnnotationView alloc] initWithAnnotation:annotation
reuseIdentifier:#"identifier"];
// create a disclosure button for map kit
UIButton *disclosure = [UIButton buttonWithType:UIButtonTypeContactAdd];
[disclosure addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self
action:#selector(disclosureTapped)]];
view.rightCalloutAccessoryView = disclosure;
view.enabled = YES;
view.image = [UIImage imageNamed:#"map_pin"];
return view;
}

For Swift 4
func mapView(mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation {
return nil
}
let reuseId = String(stringInterpolationSegment: annotation.coordinate.longitude)
var pinView = mapView.dequeueReusableAnnotationView(withIdentifier: reuseId)
if pinView == nil {
pinView = MKAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
pinView!.canShowCallout = true
pinView!.image = getRightImage(annotation.title!!)
}
let button = UIButton(type: UIButtonType.DetailDisclosure)
pinView?.rightCalloutAccessoryView = button
return pinView
}

Related

switch statement gone wrong - swift language

in Obj-c i made a switch statement which i used to move around in my app for iPad using UIsplitviewcontroller
now i want to do the same in swift... i tried for a couple of hours and now the only thing i haven't been able to try is the code because it says some sort of compile error
anyway
here's what i got in Obj-c
-(void)initialSite:(int)viewId {
UIViewController *viewController;
switch (viewId) {
case 0:{
viewController = self.initital;
NSString *star = [NSString stringWithFormat:#"Velkommen til %#'s Bog",[data valueForKey:#"navn"]];
self.navigationItem.title = star;}
break;
case 1:{
viewController = self.startSide;
NSString *start = [NSString stringWithFormat:#"%#'s Bog, start-side",[data valueForKey:#"navn"]];
self.navigationItem.title = start;}
break;
}
[self showChildViewController:viewController];
}
and here's what i come up with so far in swift. still new to this and to understand it is a little hard even tho i have the swift programming language book
here's what i got so far in swift
let viewController = UIViewController()
switch viewController {
case "initial":
let initial : UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let vc0 : UIViewController = initial.instantiateViewControllerWithIdentifier("initial") as UIViewController
self.presentViewController(vc0, animated: true, completion: nil)
let rowData: NSDictionary = self.menuItemArray[indexPath.row] as NSDictionary!
self.navigation.title = rowData["navn"] as? String
case "startSide":
let startSide : UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let vc1 : UIViewController = startSide.instantiateViewControllerWithIdentifier("startSide") as UIViewController
let rowData: NSDictionary = self.manuItemArray[indexPath.row] as NSDictionary!
self.presentViewController(vc1, animated: true, completion: nil)
self.navigation.title = rowData["navn"] as? String
default:
}
the error is : Expected declaration at the line with
let viewController = UIViewcontroller()
Let's start with your Obj-C implementation:
-(void)initialSite:(int)viewId
{
UIViewController *viewController;
switch (viewId)
{
case 0:
{
viewController = self.initital;
NSString *star = [NSString stringWithFormat:#"Velkommen til %#'s Bog",[data valueForKey:#"navn"]];
self.navigationItem.title = star;
}
break;
case 1:
{
viewController = self.startSide;
NSString *start = [NSString stringWithFormat:#"%#'s Bog, start-side",[data valueForKey:#"navn"]];
self.navigationItem.title = start;
}
break;
}
[self showChildViewController:viewController];
}
Now this same snippet in Swift:
func initialSite(viewID:Int)
{
var viewController : UIViewController?
switch (viewID)
{
case 0:
viewController = self.initial
let navn = self.data["navn"] as? String
let star = "Velkommen til \(navn)'s Bog"
self.navigationItem.title = star
case 1:
viewController = self.startSide
let navn = self.data["navn"] as? String
let star = "\(navn)'s Bog, start-side"
self.navigationItem.title = star
default:
viewController = nil
// do nothing
}
self.showChildViewController(viewController)
}
The main thing you have to remember is the difference with var vs let. Typically you will use let to create things unless those things will have their value changed later, which you use var.
The other thing is the use of optionals, with the ? suffix. This is when the value may be nil (unset), otherwise it must contain a value.
Looks like SiLo beat me to it. Anyway I have my solution so I will post it. This is how I would do it:
func initialSite(viewId: Int) -> () {
var viewController: UIViewController?
let dataValue = data["navn"];
var start: String?
switch viewId {
case 1:
viewController = self.initital
start = "Velkommen til \(dataValue)'s Bog"
case 2:
viewController = self.startSide
start = "\(dataValue)'s Bog, start-side"
default:
break;
}
self.navigationItem.title = start!
showChildViewController(viewController!)
}

Can't get new iOS 7 camera to scale inside UIPopoverController

My iOS 6 code to show the camera in a UIPopoverController works fine but iOS won't scale the camera view. Please see images below. Any suggestions would be appreciated.
Edit
public class NoRotationUIImagePickerController : UIImagePickerController
{
public override bool ShouldAutorotate ()
{
return false;
}
}
//place imagePicker into a container so that we can control the size of the popover
container = new UIViewController();
container.ContentSizeForViewInPopover = new SizeF(parentViewController.View.Frame.Width, parentViewController.View.Frame.Height);
container.View.AddSubview(_imagePicker.View);
_popOver = new UIPopoverController (container);
//If no camera is available, return false and do nothing.
if (IsCameraHardwareAvailable())
{
_imagePicker.Delegate = new PopUpGalleryPickerDelegate (_popOver, _imageSelected);
_imagePicker.SourceType = UIImagePickerControllerSourceType.Camera;
_imagePicker.AllowsEditing = false;
_imagePicker.MediaTypes = new string[] {"public.image"};
RectangleF popRectangle = new RectangleF (new PointF(parentViewController.View.Frame.Width/2, parentViewController.View.Frame.Height/2), new SizeF (1, 1));
_popOver.PresentFromRect(popRectangle, parentViewController.View, 0, true);
_imagePicker.View.Frame = container.View.Frame; //change to frame must come after popover is presented.
}
else
{
cameraAvailable = false;
}
The solution I ended up with was to make the camera full screen instead of using a popover controller.

get selected text from a uiwebview Xcode

I have a UIWebView that loads text from an htmlString.
I need when the user selects a part of the text and presses a button, i will be capable of extracting it in order to use it elsewhere, so i am using this code :
// The JS File
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"HighlightedString" ofType:#"js" inDirectory:#""];
NSData *fileData = [NSData dataWithContentsOfFile:filePath];
NSString *jsString = [[NSMutableString alloc] initWithData:fileData encoding:NSUTF8StringEncoding];
[WebV2 stringByEvaluatingJavaScriptFromString:jsString];
// The JS Function
NSString *startSearch = [NSString stringWithFormat:#"getHighlightedString()"];
[WebV2 stringByEvaluatingJavaScriptFromString:startSearch];
NSString *selectedText = [NSString stringWithFormat:#"selectedText"];
NSString * highlightedString = [WebV2 stringByEvaluatingJavaScriptFromString:selectedText];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Highlighted String"
message:highlightedString
delegate:nil
cancelButtonTitle:#"Oh Yeah"
otherButtonTitles:nil];
[alert show];
Along with HighlightedString.js :
/*!
------------------------------------------------------------------------
// Search Highlighted String
------------------------------------------------------------------------
*/
var selectedText = "";
function getHighlightedString() {
var text = window.getSelection();
selectedText = text.anchorNode.textContent.substr(text.anchorOffset, text.focusOffset - text.anchorOffset);
}
// ...
function stylizeHighlightedString() {
var range = window.getSelection().getRangeAt(0);
var selectionContents = range.extractContents();
var span = document.createElement("span");
span.appendChild(selectionContents);
span.setAttribute("class","uiWebviewHighlight");
span.style.backgroundColor = "black";
span.style.color = "white";
range.insertNode(span);
}
// helper function, recursively removes the highlights in elements and their childs
function uiWebview_RemoveAllHighlightsForElement(element) {
if (element) {
if (element.nodeType == 1) {
if (element.getAttribute("class") == "uiWebviewHighlight") {
var text = element.removeChild(element.firstChild);
element.parentNode.insertBefore(text,element);
element.parentNode.removeChild(element);
return true;
} else {
var normalize = false;
for (var i=element.childNodes.length-1; i>=0; i--) {
if (uiWebview_RemoveAllHighlightsForElement(element.childNodes[i])) {
normalize = true;
}
}
if (normalize) {
element.normalize();
}
}
}
}
return false;
}
// the main entry point to remove the highlights
function uiWebview_RemoveAllHighlights() {
selectedText = "";
uiWebview_RemoveAllHighlightsForElement(document.body);
}
I always get nothing as a result ... The alert view shows nothing...What's the problem with this code ? Any help ? Any ideas ? It will be really appreciated.
The solution was actually pretty simple and no need for all the above code!
For any future users just use:
NSString *textToSpeech = [WebV2 stringByEvaluatingJavaScriptFromString: #"window.getSelection().toString()"];
NSLog(#" -**-*--****-*---**--*-* This is the new select text %#",[WebV2 stringByEvaluatingJavaScriptFromString: #"window.getSelection().toString()"] );
NSString *theSelectedText = [self.webView stringByEvaluatingJavaScriptFromString:#"window.getSelection().toString()"];
This will pass your selection to the string variable.

Change Overlay Alpha based on MapType selection

I would like to know if its possible to change the map overlay alpha based on selecting the maptype here is my code I thought might work but it doesn't seem to. Can anyone provide some incite?
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay{
TileOverlayView *view = [[TileOverlayView alloc] initWithOverlay:overlay];
if(mapview.mapType == MKMapTypeHybrid) {
view.tileAlpha = 0.55;
} else if(mapview.mapType == MKMapTypeSatellite) {
view.tileAlpha = 0.0;
} else {
view.tileAlpha = 0.75;
}
return [view autorelease];
}
This code works fine
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id<MKOverlay>)overlay
{
MKCircleView *circleView = [[MKCircleView alloc] initWithCircle:overlay];
CGFloat alpha;
if (mapView.mapType == MKMapTypeStandard) {
alpha = 0.5f;
} else {
alpha = 1.0f;
}
circleView.fillColor = [[UIColor blackColor] colorWithAlphaComponent:alpha];
return circleView;
}
But in mapView:viewForOverlay you set alpha based on current map type. To change alpha when map change map type you need to observe mapType property using KVO. So when map type is changing you just set new alpha for all overlays. To get view for overlay use
[mapView viewForOverlay:(id<MKOverlay>)overlay];

Mapkit Annotation type when zooming in and out?

i am working with Mapkit and i am on SDK 4.2, i am having a strange bug here, in fact i have 3 annotation types, "blue.png", red.png,black.png. I am loading these by a flux and depending on the type its will select these annotation types. Everything works fine when the map is loaded i have the the different annotation view, but when i move , zoom in or zoom out the annotation view changes i.e where it was supposed to be blue.png it becomes black.png.
I am actually testing it on device.
Thank you very much :)
Hey veer the problem is that this method is called if the user pans the map to view another location and then comes back to the place where the annotations are plotted.
- (MKAnnotationView *)mapView:(MKMapView *)mapview viewForAnnotation:(id <MKAnnotation>)annotation
I have seen many sample code for map application and this in what most of the people are using.
- (MKAnnotationView *)mapView:(MKMapView *)mapview viewForAnnotation:(id <MKAnnotation>)annotation
{
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
static NSString* AnnotationIdentifier = #"AnnotationIdentifier";
MKAnnotationView *annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:AnnotationIdentifier];
if(annotationView)
return annotationView;
else
{
MKPinAnnotationView* pinView = [[[MKPinAnnotationView alloc]
initWithAnnotation:annotation reuseIdentifier:AnnotationIdentifier] autorelease];
pinView.animatesDrop=YES;
pinView.canShowCallout=YES;
pinView.draggable = YES;
pinView.pinColor = MKPinAnnotationColorGreen;
return pinView;
}
return nil;
}
i found the solution - in fact i am using a custom annotation view and having 3 diff types of images :
Soln:
- (AnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
AnnotationView *annotationView = nil;
// determine the type of annotation, and produce the correct type of annotation view for it.
AnnotationDetails* myAnnotation = (AnnotationDetails *)annotation;
if(myAnnotation.annotationType == AnnotationTypeGeo)
{
// annotation for your current position
NSString* identifier = #"geo";
AnnotationView *newAnnotationView = (AnnotationView *)[self.mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if(nil == newAnnotationView)
{
newAnnotationView = [[[AnnotationView alloc] initWithAnnotation:myAnnotation reuseIdentifier:identifier] autorelease];
}
annotationView = newAnnotationView;
}
else if(myAnnotation.annotationType == AnnotationTypeMyfriends)
{
NSString* identifier = #"friends";
AnnotationView *newAnnotationView = (AnnotationView *)[self.mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if(nil == newAnnotationView)
{
newAnnotationView = [[[AnnotationView alloc] initWithAnnotation:myAnnotation reuseIdentifier:identifier] autorelease];
}
annotationView = newAnnotationView;
}
}

Resources