Bu bölümde sizlere yazılan bir adresi iOS harita servisi içinde arayan ve koordinata çeviren bir uygulama hazırlayacağız. Yazıyı okumaya başlamadan önce aşağıdaki konuları okumanızı tavsiye ederiz;
Bu bölümde yapacağımız uygulama aslında kullanıcının bir UITextField içerisinde aramak istediği bir adresi sorgulayan ve bulunan alternatifleri bir UITableView içinde listeleyen bir uygulama olacak. Daha sonrasında kullanıcı listeden bir satıra tıkladığında adres haritada gösterilecek ve ilgili konuma bir pin atılacak. Uygulamaya başlamadan önce tasarımcı tarafından gönderilmiş uygulama tasarımına göz atalım;
Gördüğünüz gibi tasarımcımız genel görünümle beraber görsel öğelerin yüksekliklerini, ebatlarını ve bunlarla beraber yazıların yazıtipi ve büyüklüklerini detaylı bir şekilde anlatmış. Siz de projenizde profesyonel bir tasarımcıyla çalışıyorsanız bu şekilde direktifler beklemeye hazır olun (göndermezse de göndermesini talep edin). Bazı tasarımcılar PSD dosyalarının genel görünümünü PNG olarak kayıt edip özellikleri üzerine yazmayı tercih ederken bazı tasarımcılar web üzerinde yardımcı sitelere genel tasarımı koyarak uygulama detaylarını anlatırlar. Metodlar farklı gösterse de geliştirici için önemli olan kodlarken uyması gereken kurallardır ve ebat, renk RGB değeri, kullanılan yazıtipi gibi bilgileri tüm detaylarıyla bilmesi gerekir.
Şimdi uygulamaya başlamak için Xcode içerisinden yeni bir proje açalım ve Storyboard içerisinde uygulamaya ait aşağıdaki akışı oluşturalım;
Uygulamamızda UINavigationController kullanacağımızdan akışı tamamen Navigation Controller yapısına teslim ediyoruz. Burada kolaylık olması amacıyla yeni proje oluştururken Master-Detail Application seçeneğini seçebilirsiniz. İlk ekranda sadece bir UITableView ve UITextField öğesi yer alırken ikinci ekranda ise bir tek MKMapView koymamız yeterli olacaktır. MKMapView kullandığımızda projemizde Mapkit Framework'ü aktif etmeyi unutmayalım.
İlk ekranımızda daha önce yaptığımız gibi dataArray adlı bir NSMutableArray sınıfından tabloda listelenecek satırları dolduruyoruz. Bunun için UITableViewDatasource protokolünün metodlarını aşağıdaki gibi yazmamız gerekiyor;
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MyCell"];
if(cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"MyCell"];
[cell.textLabel setFont:[UIFont fontWithName:@"HelveticaNeue-Light" size:17.1f]];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
CLPlacemark *poiObject = [dataArray objectAtIndex:indexPath.row];
cell.textLabel.text = [NSString stringWithFormat:@"%@",[poiObject locality]];
double lat = poiObject.location.coordinate.latitude;
double lon = poiObject.location.coordinate.longitude;
cell.detailTextLabel.text = [NSString stringWithFormat:@"%f %f, %@",lat,lon,[poiObject ISOcountryCode]];
return cell;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [dataArray count];
}
Burada kullanılan CLPlacemark objeleri ise UITextField içine yazılan metin değerinin iOS konum servisleri tarafından sorgulanması sonrası bize geliyor. Kullanıcının araması ise klavyenin RETURN düğmesine basıldığında tetiklenecektir. Burada kullanıcının klavye hareketini UITextFieldDelegate yardımıyla yakalayarak aşağıdaki metod içerisinde değerlendiriyoruz;
-(void) loadDataArray:(NSString *) text{
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder geocodeAddressString:[NSString stringWithFormat:@"%@",text] completionHandler:^(NSArray* placemarks, NSError* error){
for (CLPlacemark* aPlacemark in placemarks)
{
[dataArray addObject:aPlacemark];
}
[myTableview reloadData];
}];
}
-(BOOL)textFieldShouldReturn:(UITextField *)textField{
[self.dataArray removeAllObjects];
[self loadDataArray: self.textField.text];
[self.textField resignFirstResponder];
return YES;
}
Kullanıcı klavyede RETURN tuşuna bastığında textFieldShouldReturn: metodu uyarılıyor ve biz kullanıcının girdiği adresi loadDataArray: metoduna göndererek sorguyu başlatıyoruz. CLGeocoder sınıfı bize girilen bir adresin koordinatlarını vermekle görevli bir sınıftır ve CoreLocation Framework içerisinde sunulur. Burada değişik alternatifler olabileceğinden bize gelen cevap bir konumlar dizisi içeriyor ve biz de buradaki konumları dataArray dizimizin içerisine atıyoruz. İşlem bittikten sonra tabloyu güncellemek için reloadData metodunu çağırmamız yeterli olacaktır.
Kullanıcı bir satıra tıkladığında ise aşağıdaki metod çalışır ve harita ekranı çalışır;
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
CLPlacemark *poiObject = [dataArray objectAtIndex:indexPath.row];
MapViewController *detail = (MapViewController *) [self.storyboard instantiateViewControllerWithIdentifier:@"map"];
[self.navigationController pushViewController:detail animated:YES];
[detail performSelector:@selector(zoomToPoi:) withObject:poiObject afterDelay:1];
}
zoomToPoi metodu CLGecocoder tarafından gönderilen konumu değişken olarak alır ve haritamızı o konumda başlatmayı sağlar. performSelector:withObject:afterDelay: kullanmamızın sebebi ise harita yüklendikten yaklaşık bir saniye sonra o bölgeye animasyonlu bir geçiş yapmayı istememizdir.
- (void) zoomToPoi:(CLPlacemark*) poiObject {
double lat = poiObject.location.coordinate.latitude;
double lon = poiObject.location.coordinate.longitude;
CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(lat, lon);
MyPin *poiPin = [[MyPin alloc] initWithName:[poiObject locality] coordinate:coordinate];
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(coordinate, 1000, 1000);
[myMapview addAnnotation:poiPin];
[myMapview setRegion:region animated:YES];
}
Bu metodda yapılan başka bir işlem ise konuma bir pin atılmasıdır. MyPin adından bir sınıftan üretilen pin, haritanın üzerine kırmızı bir iğne bırakır ve kullanıcı konumun nerede olduğunu anlar.
NOT: Bu konuyu iOS Haritalar bölümünde detaylı bir şekilde anlattığımızdan tekrar detayına inmeyeceğiz.