SUMIT LONKAR: Good afternoon, everyone. Welcome to Session 206. This is What's New In the MapKit. My name is Sumit Lonkar. I am a software engineer on the Maps team. So, we have got a jam-packed session for you this afternoon. So without further ado, let's get started.
Before we begin, first take a look at today's session's agenda. Our first topic of today is going to be improvements to existing MapKit API. Here, I will mainly talk about new features -- sorry, here, I'll mainly talk about our new APIs that we added to support our existing features. After that, I'll talk about Transit and we'll mainly focus on Transit in MapKit's perspective. And finally we will have a Flyover. Flyover is a brand new MapType to MapKit. It's been available to iOS applications since iOS 6, and now we are bringing it to you guys. And along with this topic we will have various demos for you. So you can see all these newly added API in action. So with that outline, let's jump right into our first topic today, Improvements to Existing API.
Based on comments and requests from developers like you, this year we have taken some serious effort to make sure that you and your application get best out of MapKit. These newly added API will help you to customize your MapKit experience in your application as well as enable great user experience, and for developers like you, it means way less code on your side. So, let's look at these API one by one. To start with, Pin Color Customization. So, MapKit pins, are also known as MKAnnotationView, has been an integral part of MapKit since the very beginning. They provide very concrete behavior to denote any singular point on a map. And when it comes to customization, there is not much you can do about with them. So, you can make them red or you can make them green. Or purple. And that's it. That's all you get, all you get is only three choices. And it's been like that since iOS 3. And now we are bringing you a new API that lets you customize this. So we are introducing it as a property on MKPinAnnotationView, called pinTintColor. On iOS it takes UIColor and on OS X it takes NSColor. Now, as underneath, it's UIColor and NSColor, that means you have millions of different colors that you can put on your Map.
I would like to take this opportunity to point out that we are deprecating our old API called pinColor. So, if your application is using this API, make sure that you update it to the new API that we are providing. That's all about Pin Color Customization. Let's move on to go to Callout Customization. And before we dive into callouts, I'll first take up some time to talk about callout. For those who have been using it for a long time, it is just going to be a refresher course. So, what is this callout, the callout is the white bubble that pops up when you tap on an annotation. Primarily it has four different components. One, the title. Second, you get a subtitle that goes right below the title, and you have a right accessory view and a left accessory view. Normally, these four components are good enough to provide us enough, good enough to give a little bit of information about the point or the coordinate they are representing, but the problem arises when the content size increases. For example, in this callout, all right, in this callout you can see the subtitle is getting clipped at one point. So what do you have to do to customize these callouts to fit your application needs? Well, it turns out, there are a couple of work-arounds that developers have been trying. Sometimes they run into issues, like, to start with, we have something like this in a map view where you tap -- a maps application. So, when you tap on annotations you get a POI and a callout with a Yelp review. And in order to implement a similar kind of behavior we have seen developers do something like this, where they put Emojis in their subtitle. I mean, it's fine for something like this. But what happens when you go implement something complex like this? Well, it turns out it is not a good solution. And in order to solve this problem we are introducing a new way, in terms of a property that will help you to customize the callout. The property we are introducing is called detailCalloutAccessoryView. On iOS it takes a UIView, and on OS X it takes NSView. Again, it's a UIView and NSView. That means you can customize it to a greater length. So, even if you want to use, like, a -- you can do it and it will open up the endless possibilities of customizing these callouts. Again, these callouts support auto layout, right to left languages. That means everything is in there for you, and all you need is one single line of code. Let's quickly take a look at a sample code and how one would use it in their application. So, here, I have a callback method that gets fired when you tap on an annotation. I'll start off with just setting up detailCalloutAccessory property, detailCalloutAccessoryView property to be a UIImageView. As you can see I'm just placing an image of the Taj Mahal in that callout, and that's it, that's all you need to do to customize this callout. Isn't that great? As I mentioned earlier, it is just a UIView and NSView. We are really excited to give it out to you guys and see what you guys can achieve with this thing. Hopefully we will see those results coming soon. So that's all about Callout Customization. Let's move on to Map Customizations. In this particular topic we will be talking about new handy APIs that will let you control what goes on your Map View. Like, you have a map unit inside your application, how can you control the content of this Map View? These APIs have been available to maps applications for a couple of years now and now we are bringing it to you guys. Let's start off with traffic. Now you have an ability to show any high traffic on your Map View and all you have to do is put a flag, like, set a flag on the Map View called showsTraffic. Similar to the traffic, we're also providing a way to show or hide a scale. So you can either show or hide a scale in your left top corner of your Map View. And similar to a scale, you can also show and hide compass. You might have noticed that these APIs are very similar to our existing APIs like showsPointsOfInterest or showsBuildings. We believe with the use of these APIs, you will be able to customize Map View inside your application and provide a great user experience. So that's Map Customization. Other than maps, other than these APIs we talked about, we have various other improvements to MapKit as well. First of all, a time zone support. We have added a time zones property on our MK map item. You can use that property to get the associated time zone. You can use it with CLGeocoder. So you can find out a time zone associated with a particular coordinate. Or you can also use it with MKLocalSearch, so, you can search an area for a point of interest or anything that you would like to search. And you can find out a time zone associated with that. Besides that, we have also done various improvements to MapKit for better Swift compatibility, and we also added a WatchKit support to launch maps applications on your watch from your own application. So that's it, so that's all the improvements that we have done to existing features in MapKit. Let's move on to the next topic and personal favorite of mine, Transit.
We were pretty excited about yesterday's keynote, with the moment we announced the new feature for maps application Transit. And today we will mainly focus on what it means to MapKit. We have worked really hard on this feature. And while designing this feature we kept our user at the center of the development process. And in order to provide a similar kind of experience in your application, we would like you to leverage maps application to provide a similar experience. And the way we are going to do that is by providing you a distinct entry point to a Maps Transit feature. Let's look at this point one by one. First one, ability to request a Transit ETA. If you use MKDirections protocol, MKDirections class and related APIs before, then you know, you might be aware of these two TransportType that we already support, automobile and walking. You can request directions and ETAs for these two transport types. And this year we are adding a new TransportType, MKDirectionsTransportType, Transit. With this TransportType, you will be able to request ETAs. And I would like to point it out, you will only, as of now you will only request ETAs for Transit. You won't get a Transit direction. So, let's see how you can -- before we move on to a sample code, let's see how you can, what you get besides ETA. Well, you get expected arrival timing and expected departure timing. Given the frequency, given the nature of the frequency of our transit varies based on the time of the day and a place, it is really important that we provide this information. We believe with this information, you will be able to give out a great user experience to your application user base. Let's take a look at a sample code, how can we request these Transit ETAs. Here, I have a helper function called getTransitETA. So, I'll start off with creating an MKDirectionsRequest. After that I'll set a source and a destination on it, and once I have that, I'll set our transport type to be Transit because we are interested in getting our Transit ETA. Once, after that I will create MKDirections object using the request that we just created, and I'll call it calculate ETA With Completion Handler on that direction object, and in CompletionHandler I will handle the response that is coming back from the server.
So, that's a Transit ETA. Now, once we have the Transit ETA, in order to provide a complete experience we are giving you a way to launch maps applications into a Transit mode. As of now you can launch maps using various different launch options on a map, along with a map item, and the MKLaunchOptionsDirectionsModeKey helps you to point out which maps application mode you would like to launch in. So as of now, we are supporting a Driving mode and a Walking mode, and now with iOS 9 we are also introducing a Transit mode.
By using this mode, you will be able to launch maps application from your application. Let's quickly take a look at a sample code here. So, here, I have a helper function called openInMapsTransit, which takes a coordinate. And I will just basically start off with creating an MK map item with that parsing coordinate. After that I'll create a dictionary launch options with the mode set to be Transit. And once I have that, all I have to do is call openInMapsWithLaunchOptions on that map item. It will basically launch our maps application in Transit mode with the mapped item to be a destination. So that is enough of our talking. Let's see all these APIs in action.
All right. So for this demo purpose I have created a city tour application for San Francisco. It is basically just a simple map view with various different annotations in it. I'm just going to quickly run it so you can see what I have so far.
So, as you can see, we have a map of San Francisco and I plotted various different annotations with the landmarks, like we have Sutro Tower over here, we have Golden Gate bridge, and all that, and I have also taken the liberty to set the pin colors on these. So if I scroll down to the viewForAnnotation callback, you can see I have set in a pin tint color property to customize these pin colors. This is okay. As the demo progresses we will try to customize this more and more. To begin with, what I'm going to do is I'm going to add a Transit ETA into a subtitle. So in order to do so I have created a simple helper function.
I am going to drag and drop that in here. So I have this helper function that basically takes our annotation, which is a landmark class for local object. And then I will create a MKDirectionsRequest in there. So you can see I have created an MKDirectionsRequest. After that I'm just setting a source and a destination on that request.
And finally I'm setting a transport type to be Transit because we are interested in a Transit ETA.
Once I have that, I'm going to go and create an MKDirections object.
So in here I have created an MKDirections object using the request and in CompletionHandler I'm just setting an annotation.subtitle to be our estimated time of arrival. And I am quickly going to call this function before I drop my annotation on a map view. So let's call that function here LandMarkPin.
So, all right, let's run it.
There we go, so city hall is about 22 minutes from Moscone West by using a public transport. Let's check out some other pins. Ferry Building, it's 17 minutes. So this is nice. I mean, this gives initial information to your user like how long will it take to go to this destination using Transit, but in order to provide a complete Transit experience we have to find out a way to bring them to a maps application. And for this demo purpose, what I am going to do is, I'm going to put a right callout accessory view on my callout, and when I tap it, I will take the user to a maps application.
So we quickly stop it, and let's go back to our callback method. And in here I am going to set a rightCalloutAccessoryView on my AnnotationView.
I added my rightCalloutAccessoryView. Let's run it.
So you can see a right callout accessory view. We have added a bus icon here. Nothing is happening because we haven't implemented the callback method that gets called every single time a callout accessory control is tapped. So let's quickly go and add that method down here.
So this is the callback method that gets called every time a callout control accessory is pressed.
Once I have this, I am going to add my code to launch a given map item into a maps application. So here I start off with creating a dictionary object with the mode Key, and the mode key set to be Transit. After that by getting a coordinate from the past annotation I'm going to create an MKMapItem. And once I have that, I am going to use open in launch options on mapItem to launch this map item into a Transit mode. Let's quickly go ahead and run our application again.
Let's see, Ferry Building.
Tap on it and there we go. We have a maps application into a Transit mode and you can see it takes 18 minutes by bus number 40. And let's go back to our sample app again and try something else.
Let's see if we got a response for Sutro. Yeah, there we go. That's our response. Again 45 minutes by Transit. That's fairly long. Oh, I see. It is something wrong. Oh, bus stops moved, so probably that's the reason, long time. Anyway, that's a Transit experience in a MapKit. Now I would like to talk about how we previously talked about the callout customization. Now let's go and see how can we use those callouts in this, our sample app.
All right. So, again, we are going to go back to our callback method that gets called every single time the annotation is tapped. And down here I'm just going to set a detailed callout accessory property on this view. For the data that I'm getting for these landmarks I have some of the images.
So let's set a UIImageView in a detailCallout and see how they look in our annotation.
So, here I'm just reading my image data, I'm reading my image name from a plist that I'm parsing, and then I'm creating a UIImage, and after that I'm creating a UIImageView and setting it on a detailCalloutAccessoryView.
So let's run this thing. Okay. All right.
So I think I have an image for Golden Gate Bridge. So let's go and take a look at it. So there we go. That's a nice image of the Golden Gate Bridge. Let's see what else I have. I have the Ferry Building as well. Okay, that's current location.
All right. Okay. So, Transamerica Pyramid doesn't have a, Transamerica Pyramid doesn't have an image. So you can see when we set a detail callout accessory view on a callout, a detail callout accessory, we will always get precedence or a subtitle. For Golden Gate Bridge we did add a detail, we did have a subtitle, but as soon as we set a detail callout accessory view on it, it got a precedence or a subtitle. So, for some of these other landmarks, I don't have images. So, let's add text in there. So, I have also created a text view that will -- so here I have a custom text view that basically I just have set some height and weight on it. And that will allow me to show the content in our detail callout accessory view. Similar to the images, I'm reading data from my plist that I have been using to plot these landmarks. I just set it that detailTextView to be a detailCalloutAccessoryView.
All right. So I'm quickly going to run it again.
Okay. All right. So let's see.
As you can see now we have a nice text view down here in Sutro Tower callout. Let's check on something else.
Same thing, for City Hall we also have a nice text. So here I have like a one callout with a subtitle, one callout with a UIImageView and one callout with a TextView. That's all the beauty of this API. We are really excited to offer it to you and I am damn sure that you guys will come up with something amazing.
So what we learn from this demo, we learn how we can customize our pin colors, we learn how we can customize our callouts. We also learn how to request Transit ETAs and we also learn how to bring users to a maps application to provide a rich transit experience. That's all from my end. To talk about Flyover, I would like to call upon Elisabeth.
ELISABETH LINDKVIST: Okay.
Right, let's talk about Flyover.
My name is Elisabeth Lindkvist, and I'm also an engineer on the maps team. And these are the things that I will be talking to you about today. So, first of all, what is Flyover? How will it work in your application? How do you set the right region and handle the camera when you are using Flyover? And I will also discuss how Flyover will work together with some of our existing MapKit API.
But to start with, what do we actually mean by Flyover? For example, this is Flyover.
It's photo-realistic 3D models of various cities and landmarks.
They are available in many different places all around the world. And they have been available in the maps application since iOS 6.
And we are now giving you the opportunity to show these interactive 3D views to your users. As you might have noticed in the maps application where satellite imagery is not available you will instead see flat satellite imagery being displayed on top of a 3D height map which represents the terrain. And this will also be the case in your apps. Another important aspect of Flyover is this: it is being displayed on a globe rather than being projected into 2D like our other map types are. This one has some implications for how you handle your region setting.
And this is something that I will be returning to shortly.
So, what do you need to do to get a Flyover view in your application? If you used MapKit before, I'm sure you are familiar with MK map type, which is the property you set on an MK map view, in order to choose which type of data you will be displaying.
We have standard, which is a regular map.
We have satellite, which is a top-down satellite view. And we have hybrid, which adds things like roads and labels and points of interest to the satellite view.
And we are now introducing two new map types, Satellite Flyover and Hybrid Flyover.
So in order to display something like this in your app, what you would do is just set the map type of your map view to Satellite Flyover.
If you want to add things such as labels, points of interest, roads, and borders, you would instead use the Hybrid Flyover map type. Now, as I mentioned, there are some things you really need to consider when using Flyover. One of the most important ones is how you set the visible region of your map.
You might be familiar with the several methods in MapKit that use rectangles such as MKCoordinateRegion and MKMapRect in order to set and get the visible region of your map. However, the visible area of your map view is not always a rectangle.
In iOS 7 we introduced the possibility to view a pitched map view where you are viewing the map at an angle. And when you do that, the visible area will not actually be a perfect rectangle, and this will also be the case in Flyover as you can view pitched map views there as well.
Now, if we take a look at this region and zoom out a bit we can see the actual shape of the visible area.
And what we do in this case is that we define the visible region of this map as the rectangle which is enclosing what you are actually seeing on screen. So it will be the blue rectangle in this case. And this will work exactly in the same way in Flyover. The visible region will be defined as the rectangle that is enclosing whatever you see on screen.
Now, in Flyover, a view does not necessarily have to be pitched in order to not be rectangular. If you have a region such as this, which is fairly large, and you try to set the visible region to the blue rectangle in this case you end up with something like this.
And the point here is that a rectangular representation will always be an approximation since Flyover is being shown on a globe.
And, also, if you have a very large region there will be some areas that are not actually displayed. So, in this case, parts of the visible region are actually behind the globe.
So, the recommended way, even though there are some cases where rectangular region setting works just fine in Flyover and with pitched map views, for example, if you have a top-down view where if you're very zoomed in, the recommended way to make sure that you are really displaying exactly the part of the world you want to is to use MKMapCamera.
MKMapCamera was also introduced in iOS 7 in 2013. And for more detailed information about MKMapCamera, and also about region setting in general, I really recommend that you check out Putting MapKit in Perspective, which is a talk from 2013.
But I will briefly recap a bit about MKMapCamera.
It has four basic properties.
The center coordinate, which is the position in the world that you want to be shown in the middle of your screen.
The heading which is the direction the camera will be looking in.
The pitch, how tilted the view is, at what angle you are looking at the map, and the altitude, which is the height in meters above the map where you want your camera to be positioned. There is also a convenience initializer for MKMapCamera, which takes the center coordinates and the eye coordinates, where you want the camera to be positioned, and the eye altitude, how high up you want the camera to be, and gives you back the camera which is looking at that center coordinate from the eye coordinate.
So, however, in Flyover there is terrain and buildings and all other sorts of interesting things. And that means that the altitude is actually not as straightforward as you might think. For example, is it the height above the buildings? The height above the terrain? Or some sort of sea level? So instead the distance between the center coordinates and the camera is actually a much better measure for this case. And this is where we're adding a new initializer to MKMapCamera. And let me go through quickly what this does.
You will start with the center coordinates, the position you want to be in the middle of the screen. And you will then specify a distance in meters, how far away from the center coordinate you want the camera to be positioned. And notice how this differs from the altitude. You will also specify the pitch, how angled you want the camera to be, and the heading, the direction you want to be looking in.
And using this initializer you can get a camera which is looking precisely where you want to without having to worry about what sort of terrain or buildings happens to be beneath your camera.
And I will now give a short demo to show some of the cool things you can do with Flyover.
Okay. So Sumit was showing you a tour application earlier. And I have a similar application here running on my Mac. You can see the landmarks here.
For example here, Cliff House.
And as you might remember there were some of these locations that we did not actually have any images for. And I thought we could use Flyover in order to correct that.
So what I will be doing is, that I will be adding a detail callout accessory views to my callouts here. And I will use the MKMap snapshot in order to generate images from Flyover, to set as the image of the detail callout accessory view. The MKMap snapshot is very useful when you only really need a static image of a map, when you don't need it to be interactive.
So I'm going to add a few options for the snapshotter, and the most important one here being that I'm setting the mapType to Satellite Flyover.
I will then create an MKMapCamera using our new initializer to look at the coordinates of the annotation.
And I will then use these options to create an MKMap snapshotter.
I'll start the snapshotter and if it completes without any error, I will use the resulting image as the image on my detail callout accessory view. Let's of course, call this function.
Okay. Let's take a look at what it looks like now. So if I recall correctly, Cliff House was one of those that we didn't have an image for. And look at that, now we do. ELISABETH LINDKVIST: And yeah, I think we have a few other ones here. Like City Hall, for example. Now, that's was pretty cool, but Flyover views are of course also interactive, so I'm thinking we can add a little animation to this view.
And I created a new ViewController which doesn't really do much yet but it has an MKMapView.
And I will add some constants that I think will be useful.
And then I will set up the map view.
And so as we can note here I'm also setting my map type to Satellite Flyover.
I'm hiding the compass and the zoom controls that are visible in OS X.
I'm also creating an MKMapCamera which initially looks at the coordinates of the landmark.
And that's about all the setup I need.
Then I'm going to create a couple of additionally MKMapCameras.
First of all I have one which is a bit tilted down, my pitched camera.
And I'm also adding a rotation here. So it will do a little spin around.
And as MKMapCamera is an animatable property in MKMapView, I will do a little animation in order to switch between these.
So here I am adding first a little short animation which will set the camera to my pitched camera, and we will tilt the view down a bit, and I am then adding a little longer animation which will do a little spin around. In my main View Controller I have added a little right callout accessory view here which will open my new View Controller.
So let's add that button as well.
Okay. Let's take another look at Cliff House. There we go. And I have my little button here, and we are tilting down.
And spinning around.
This was fun. We'll just look at this one, too, because I think it looks really cool.
There we go. Transamerica Pyramid, too.
Okay. So now we have seen some of the things that you can do with Flyover. So let's get back to the presentation.
As I said at the beginning there are also some parts of the existing MapKit API that I would like to talk about, how they would work together with Flyover.
And I'll start with MK annotations. MK annotations are used to annotate a single coordinate of the map and the most common use case is the pins that we have been working with today.
If you are showing buildings on the standard map type, annotations will be placed on top of those.
And this will also be the case when you are using the Flyover map types. Annotations will be placed on top of any buildings, trees, large boats, statues, whatever you may find when you are exploring Flyover.
And next, MKOverlays. Overlays are used to highlight areas of the map rather than just a single coordinate.
And if you are showing buildings on a 3D map in the standard map type, you will notice that overlays are being occluded by the buildings.
This will work precisely in the same way in Flyover. Any overlays you have will be occluded by Flyover buildings and trees.
Something like that.
However, overlays will be drawn on top of the terrain so that they will follow the ground.
Something like that. So I think that's about everything you need to know in order to get started with using Flyover in your apps and I can't wait to see what you will be doing with it. To summarize a bit what we have been talking about today, we have added some new ways for you to customize your pins, your callouts, and the way you display your map with traffic, and compass, and scale.
We've added Transit ETA requests and ways for you to launch into the maps apps to show Transit directions.
And we've also added the Satellite Flyover and Hybrid Flyover map types so that you can show photo-realistic 3D models and satellite imagery on terrain in your apps. For more information, please take a look at the MapKit documentation and the Developer Forums.
Thank you so much for coming. [ Applause ]
Looking for something specific? Enter a topic above and jump straight to the good stuff.
An error occurred when submitting your query. Please check your Internet connection and try again.