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!