iPhone/iPad uygulamalarında yaygın olarak kullanılan bileşenlerle ilgili yazılarıma devam ediyorum. Bu yazıda bahsedeceğim bileşen UIWebView. Bu bileşen adından da anlayabileceğiniz gibi bir web tarayıcısı. Safari gibi bir tarayıcıdan tek eksiği navigasyon ve benzeri işlevleri yapabilmek için tuşlara değil, Objective-C kodu aracılığıyla kullanılabilen metod ve özelliklere sahip olması. Bu yazımda göstereceğim örnek uygulamada geri git, ileri git, sayfayı yenile gibi tuşlar ve sitenin gösterileceği bir alandan ibaret olan basit bir web tarayıcısı. Bu örneği takip ederken UIWebView ile bir tarayıcının yerine getirmesi gereken temel işlevleri kod içerisinden nasıl yapılabileceğini öğreneceksiniz.
İşe her zaman gibi "Ornek" adında, View-Based Application taslağını kullanan bir proje yaratarak başlayın. Sonra "OrnekViewController.xib" adlı arayüz dosyasını açın ve arayüze 4 tane tuş (UIButton), bir tane yazı kutusu (UITextField), bir tane tarayıcı (UIWebView) ve bir tane de aktivite göstergesi (UIActivityIndıcatorView) ekleyin. Bileşenlerin yerlerini ve tuşların üzerindeki yazıları şekildeki gibi değiştirin. Arayüzden de anlayabileceğiniz üzere yazı kutusuna adres girip üstteki "Git" tuşuna bastığınızda tarayıcı o adrese gidecek. Alttaki 3 tuş da en temel 3 tarayıcı işlevini gerçekleştirecek.
Sonraki aşama, gereken Outlet ve özellikleri belirlemek. UIWebView'e Objective-C kodu içerisinden erişileceği ve dolayısıyla onun için bir Outlet gerekeceği açık. Tarayıcının hangi adrese yönlendirileceği yazı kutusundan alınacak, dolayısı ile onun için de bir Outlet gerekiyor. Tarayıcı sayfayı yüklemekle meşgulken kullanıcıya bir aktivite göstergesi gösterilecek. Göstergeyi kod içerisidnen gösterip gizleyebilmek amacıyla onun için de bir Outlet tanımlamanız gerekli. Bunların dışında her bir tuş için, tuşa basıldığında çağrılacak bir metod tanımlamanız gerekiyor. Tanımlamalara ek olarak, ViewController'ınızın UIWebViewDelegate ve UITextFieldDelegate protokellerine uyması gerekiyor. Nededinini ilerde göreceksiniz. "OrnekViewController.h" adlı Objective-C header dosyasını açıp gerekli tüm tanımlamaları yaparak şu hale getirin:
#import <UIKit/UIKit.h>
@interface OrnekViewController : UIViewController
<UIWebViewDelegate, UITextFieldDelegate>
{}
@property (nonatomic,retain) IBOutlet UIWebView *webView;
@property (nonatomic,retain) IBOutlet UITextField *adresKutusu;
@property (nonatomic,retain) IBOutlet UIActivityIndicatorView *gosterge;
- (IBAction)adreseGit:(id)sender;
- (IBAction)geriGit:(id)sender;
- (IBAction)ileriGit:(id)sender;
- (IBAction)yenile:(id)sender;
@end
Şimdi arayüz dosyasına dönüp Outlet ve metodlar ile bileşenler arasında gerekli bağlantıları yapın. WebView ve TextField bileşenlerinin delegate özelliklerini de ViewController'ınıza bağlamayı unutmayın. Sonra Activity Indicator'ün Hide When Stopped özelliğini yanına bir tik koyarak aktif edin. Bu özelliği açmanız, göstergenin kod içerisinden durdurulduğunda otomatik olarak gizlenmesini sağlayacak. Son olarak da UIWebView'ın Scales Page To Fit özelliğini aktif edin. Bu da UIWebView'in web sayfasını yükleme işlemi sonrasında sayfanın tamamını gösterecek şekilde zoom out yapmasını sağlayacak.
Sıra "OrnekViewController.m" adlı Objective-C kod dosyasına dönüp asıl işlevselliği yerine getirecek olan kodu yazmaya geldi. Öncelikle her zamanki gibi, XCode'un oluşturmuş olduğu ancak sizin kullanmayacağınız metod implementasyonlarını silin. Tanımladığınız Outlet'lerin her biri için @synthesize direktiflerini ve bellek iade bölümlerini ekleyin. Bu sefer viewDidLoad metodunda hiçbir şey yapmayacağız o yüzden onu da silebilirsiniz. Bu işlemleri yaptıktan sonra kod şu halde olmalı:
#import "OrnekViewController.h"
@implementation OrnekViewController
@synthesize webView, adresKutusu, gosterge;
- (void)viewDidUnload
{
self.webView = nil;
self.adresKutusu = nil;
self.gosterge = nil;
}
- (void)dealloc
{
[super dealloc];
[webView release];
[adresKutusu release];
[gosterge release];
}
@end
Şimdi tek tek her tuşun çağıracağı metodu yazın. İlk olarak tarayıcıyı adres kutusuna yazmış olduğunuz adrese yönlendirecek olan metodu aşağıdaki şekilde yazın.
- (IBAction)adreseGit:(id)sender
{
// Adres kutusunda yazılı olan adresi al
NSString *adres = adresKutusu.text;
// Eğer adres http:// ile başlamıyorsa başına http:// ekle
if (adres.length > 7 && [[adres substringToIndex:7] compare:@"http://" options:NSCaseInsensitiveSearch] != NSOrderedSame)
{
adres = [@"http://" stringByAppendingString:adres];
// Değişikliği adres kutusuna da yansıt
adresKutusu.text = adres;
}
// Hedef URL'yi oluştur
NSURL* URL = [NSURL URLWithString:adres];
// Hedef URL'ye gidecek olan Request'i oluştur
NSURLRequest* request = [NSURLRequest requestWithURL:URL];
// WebView'a Request'i gönder
[webView loadRequest:request];
}
Gördüğünüz gibi UIWebView'i bir adrese yönlendirmek için, öncelikle adresi içeren bir URL ile oluşturulmuş bir request yaratmanız gerekiyor. Daha sonra UIWebView'ın loadRequest: metoduna bu request'i vererek yönlendirme işlemini başlatmış oluyorsunuz. Burada URL'yi oluşturmadan önce adresin başında http:// olduğundan emin olduk çünkü eğer öyle olmazsa UIWebView hangi protokolü kullanacağını bilemez. Uygulamayı bu haliyle çalıştırırsanız eğer internete bağlı olan bir cihazdaysanız WebView'in istediğiniz sayfayı açtığını, ancak klavyenin ekrandan gitmemek konusunda ısrarcı olabildiğini göreceksiniz
. Şimdi geri, ileri ve yenile tuşlarının metodlarının implementasyonlarını da aşağıdaki gibi yapın ve klayveyi ekrandan götürmek için gerekli olan delegate metodunun implemetasyonunu eklemeyi de unutmayın.
- (IBAction)geriGit:(id)sender
{
if ([webView canGoBack])
[webView goBack];
}
- (IBAction)ileriGit:(id)sender
{
if ([webView canGoForward])
[webView goForward];
}
- (IBAction)yenile:(id)sender
{
[webView reload];
}
// Klavyeden kurtulma metodu
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
return NO;
}
Gördüğünüz gibi bu 3 işlevin her biri sadece tek bir metod çağrısı ile yapılabiliyor. geriGit: ve ileriGit: metodlarında işi sadece UIWebView sınıfının goBack ve goForward metodlarını çağırarak bitirebilirdik ancak bunu yapmaktansa ileri veya geri gitmenin mümkün olup olmadığını yine basit 2 metod çağrısı ile kontrol ettik ve sadece mümkün olduğu durumlarda işlem yaptık. Bunu yapmanız şart değil, sadece nasıl yapıldığını görmeniz açısından ekledim buraya. Uygulamayı tekrar çalıştırırsanız artık tüm tuşların işlerini yaptıklarını görürsünüz.
Dikkat ettiyseniz henüz yükleme göstergesi ortalıkta görünmüyor. Şimdi sıra onu eklemeye geldi. Yapmanız gereken şey, tarayıcı bir sayfayı yüklemeye başladığında göstergenin animasyonunu başlatmak ve yükleme işleme başarıyla tamamlandığı ya da bir hata oluşuğu zaman da durdurmak. Daha önceden arayüz editöründe işaretlemiş olduğunuz Hide When Stopped özelliği gizleme işlemini sizin yerinize yapacak. Şimdi buradaki sorun yükleme işleminin ne zaman başlayıp ne zaman başarıyla tamamlandığını ya da ne zaman bir hata oluştuğunu nereden bileceğiniz. Sorunun cevabı UIWebViewDelegate protokülünde tanımlanmış olan 3 metodda yatıyor. UIWebView, yükleme işlemine başladığında delegate'i olarak ayarlanmış olan nesnenin webViewDidStartLoad: metodunu, yükleme işlemini başarıyla tamamladığında webViewDidFinishLoad: metodunu, bir hatayla karşılaştığında ise webView:didFailLoadWithError: metodunu çağırıyor. Hatırlarsanız daha önce .h dosyasında ViewController'ınızın bu protokolü desteklediğini belirtmiş ve arayüz editöründen de WebView'inizin delagete özelliğini de ona bağlamıştınız. O yüzden bu üç metodun implementasyonlarını aşağıdaki şekilde yaparak göstergenin düzgün çalışmasını sağlayabilirsiniz.
- (void)webViewDidStartLoad:(UIWebView *)webView
{
[gosterge startAnimating];
}
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
[gosterge stopAnimating];
adresKutusu.text = [webView.request.URL absoluteString];
}
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
{
[gosterge stopAnimating];
}
Böylece göstergenin animasyonunu sayfa yüklenmeye başladığında başlatıp, sayfa yüklendiğinde ya da bir hata olduğunda durdurmuş olduk. Ayrıca sayfanın başarıyla yüklenmiş olması durumunda adres kutusu içerisinde görülen adresi de güncelledik. Bunu yapmazsanız, yazdığınız adresteki sunucunun sizi başka bir adrese yönlendirmesi durumunda, adres kutusunda yazan adres ile bakmakta olduğunuz sayfanın gerçek adresi birbirini tutmayacaktır. Şimdi uygulamanın şu anki halinin bir ekran görüntüsünü koyayım:
Bu haliyle uygulama basit bir web tarayıcısı haline geldi. Ancak hala hata kontrolü yok. Saçma sapan bir adres yazarsanız tarayıcının hiçbir şey yapmadığını görebilirsiniz. Böyle durumlarda en azından kullanıcıya bir hata mesajı göstermek isterseniz, bunu webView:didFailLoadWithError: metodu içerisinde yapabilirsiniz. Metodun içeriğini şu hale getirin.
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
{
[gosterge stopAnimating];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Hata" message:[error localizedDescription] delegate:nil cancelButtonTitle:@"Tamam" otherButtonTitles:nil];
[alert show];
[alert release];
}
Bu değişiklikten sonra UIWebView ile ilgili her türlü hata size bir mesaj kutusu ile bildirilecektir. Burada her türlü hata mesajını gösterdim ancak pratikte burada hata olarak kabul edilen bazı durumlar gerçekte hata olarak kabul edilmeyebilir. Buna en güzel örnek bir sayfanın yüklenme işlemi tam bitmeden ileri/geri tuşlarını kullanarak başka bir sayfaya geçmeye kalkmak. Uygulama böyle durumlarda da hata mesajı gösterecektir. Bu sebeple hata mesajlarını göstermeden önce elemek gerekiyor. Ancak o buranın konusu değil o yüzden şimdi ondan bahsetmeyeceğim. Uygulamayı çalıştırıp adres çubuğuna saçma sapan bir adres girmeyi deneyin ve hata kontrolünün çalıştığını görün.
Bu yazımı okuyarak iPhone SDK ile basit bir web tarayıcının nasıl yapılacağını öğrenmiş oldunuz. UIWebView sınıfının burada bahsetmediğim onlarda diğer özelliği için dökümantasyona bakabilirsiniz.