Usando iOS MapKit e CoreLocation com Delphi Prism e MonoTouch
Na minha opinião Maps (Mapas) é um dos aplicativos mais úteis no iPhone, sempre o utilizamos para nos guiar no trânsito, localizar algum restaurante, supermercado, posto de gasolina ou algo do gênero perto de onde estamos. Neste post vou mostrar como usar o MapKit e CoreLocation framework parte do iOS SDK, ambos permitem utilizar as funcionalidades relacionadas a mapas em sua aplicação.
O MapKit fornece uma apresentação visual de informações geográficas com dados e imagens do Google Maps usando o controle MKMapView, o mesmo usado no aplicativo Maps do iPhone. O MapKit está representado no MonoTouch através do namespace MonoTouch.MapKit.
CoreLocation funciona em vários dispositivos iOS usando uma variedade de tecnologias para determinar a posição e com uma bússola embutida no dispositivo consegue fornecer a posição em que o aparelho está apontando. Usando essas informações você pode determinar onde os usuários estão e em que direção o seu dispositivo está apontando, através das alterações no monitoramento você tem como determinar a velocidade e distância em que os usuários estão se locomovendo. O CoreLocation framework está representando no MonoTouch através do namespace MonoTouch.CoreLocation onde trabalha com dois tipos de informação: Location e Heading.
Vou assumir que você já assistiu minha apresentação introdutoria sobre iPhone (em inglês) na qual eu explico como criar um simples Web browser para iPhone usando Mono IDE e Interface Builder, pois neste post vou direto a implementação.
Para usar o MKMapView você precisa apenas arrastar e soltar o controle no seu Window através do Interface Builder, além claro do controle Segmented Control que irá permitir a troca do tipo de visão do Mapa (Standard, Hybrid, Satellite).
Com base no endereço informado a aplicação irá adicionar um PIN no mapa referente ao endereço exato, para adicionar um marcador PIN ao mapa será necessário criar e adicionar MKAnnotations ao MKMapView. MKAnnotation é uma classe abstrata e tem que ser implementada na sua aplicação como mostro no código abaixo.
MyAnnotation nested in AppDelegate = public class(MKAnnotation)
private
_coordinate: CLLocationCoordinate2D;
_title: System.String;
_subtitle: System.String;
public
property Coordinate : CLLocationCoordinate2D read _coordinate write _coordinate;override;
property Title: System.String read _title; override;
property Subtitle: System.String read _subtitle; override;
// The custom constructor is required to pass the values to this class,
// because in the MKAnnotation base the properties are read-only
constructor (l: CLLocationCoordinate2D; t: System.String; s: System.String);
end;
Agora tenho que implementar o Search Bar delegate responsável por gerenciar os eventos gerados, o exemplo abaixo não é uma implementação completa do UISearchDelegate, mas implementa o necessário para gerenciar as mudanças de comportamente na hora de efetuar uma busca (search).
O botão de busca (Search) obtem a latitude/longitude utilizando o web service do Google e utilizando a classe MyAnnotation irá adicionar um PIN ao mapa. Lembre-se que você precisa obter uma chave para utilizar a API do Google Maps através do link http://code.google.com/apis/maps/signup.html para usar esta aplicação, associe o seu Google Maps Key a variável GoogleMapsKey.
MySearchBarDelegate nested in AppDelegate = public class(UISearchBarDelegate)
private
app: AppDelegate;
lastResult: MyAnnotation;
GoogleMapsKey:String := String.Empty; // Define you google maps key here.
// Keep a reference to the application so we can access the UIControls.
// This needs to be an internal class to access those (private) controls.
public
constructor (a: AppDelegate);
// Method for the searchbar to call when the user wants to search,
// where we create and call the Geocoder class. Note that we are
// calling it synchronously which is undesirable in a "real"
// application.
method SearchButtonClicked(searchBar: UISearchBar); override;
end;
method AppDelegate.MySearchBarDelegate.SearchButtonClicked(searchBar: UISearchBar);
begin
var g := new Geocoder(GoogleMapsKey);
var location: CLLocationCoordinate2D;
searchBar.ResignFirstResponder;
UIApplication.SharedApplication.NetworkActivityIndicatorVisible := true;
// synchronous webservice call
if g.Locate(searchBar.Text, out location) then begin
if lastResult <> nil then
begin
// if there is already a pin on the map, remove it
app.Map.RemoveAnnotation(lastResult)
end;
app.Map.SetCenterCoordinate(location, true);
var pin := new MyAnnotation(location, searchBar.Text, location.Latitude.ToString + ',' + location.Longitude.ToString);
app.Map.AddAnnotationObject(pin);
lastResult := pin;
end
else
begin
// display a message that the webservice call didn't work
using alert := new UIAlertView('Not found', 'No match found for ' + searchBar.Text, nil, 'OK', nil) do
begin
alert.Show()
end
end;
UIApplication.SharedApplication.NetworkActivityIndicatorVisible := false;
end;
Para finalizar abaixo temos a implementação que busca a latitude/longitude usando o web services do Google, temos apenas que passar o endereço e o Google irá retornar a informação.
interface
uses
System,
System.Xml,
System.IO,
System.Net,
MonoTouch.CoreLocation;
// Documentation for the service http://code.google.com/apis/maps/documentation/geocoding/
type
Geocoder = public class
public
constructor (key: System.String);
// Sign up for a Google Maps key http://code.google.com/apis/maps/signup.html
private
var _GoogleMapsKey: System.String;
var xmlString: System.String := '';
public
method Locate(query: System.String; out return: CLLocationCoordinate2D): System.Boolean;
private
// Retrieve a Url via WebClient
class method GetUrl(url: System.String): System.String;
end;
implementation
constructor Geocoder(key: System.String);
begin
_GoogleMapsKey := key;
end;
method Geocoder.Locate(query: System.String; out return: CLLocationCoordinate2D): System.Boolean;
var
url: System.String := 'http://maps.google.com/maps/geo?q={0}&output=xml&key=' + _GoogleMapsKey;
coords: XmlNode := nil;
xd: XmlDocument;
xnm: XmlNamespaceManager;
gl: System.String;
coordinateArray: array of System.String;
begin
url := String.Format(url, query);
return := new CLLocationCoordinate2D(0, 0);
try
xmlString := GetUrl(url);
xd := new XmlDocument();
xd.LoadXml(xmlString);
xnm := new XmlNamespaceManager(xd.NameTable);
coords := xd.GetElementsByTagName('coordinates')[0]
except
end;
if coords <> nil then begin
coordinateArray := coords.InnerText.Split(',');
if coordinateArray.Length >= 2 then begin
gl := Convert.ToDouble(coordinateArray[1].ToString()).ToString + ',' + Convert.ToDouble(coordinateArray[0].ToString());
return := new CLLocationCoordinate2D(Convert.ToDouble(coordinateArray[1].ToString()),
Convert.ToDouble(coordinateArray[0].ToString()));
exit true
end
end;
exit false
end;
class method Geocoder.GetUrl(url: System.String): System.String;
var
return: System.String := System.String.Empty;
client: System.Net.WebClient := new WebClient();
begin
using strm: Stream := client.OpenRead(url) do
begin
var sr: StreamReader := new StreamReader(strm);
return := sr.ReadToEnd()
end;
exit return;
end;
end.
Quando executamos a aplicação podemos visualizar o mapa de 3 formas diferentes conforme as figura abaixo, o PIN (em vermelho) está na posição onde está localizado nosso escritório aqui em Scotts Valley.



O código fonte está disponível para download no CodeCentral.








Trackbacks & Pingbacks
[…] This post was mentioned on Twitter by Andreano Lanusse. Andreano Lanusse said: Blog post: Usando iOS MapKit e CoreLocation com Delphi Prism e MonoTouch http://bit.ly/gH6eb3 #ios #iphone […]
Deixe uma resposta
Want to join the discussion?Feel free to contribute!