Tuesday 2 August 2011

UIAlertView'da Text Field etc.

uialertview'a textfield ekleme ve programatik olarak uialertview'ı kapatma.

AppStore'dan uygulama indirirken bize username/password girmemiz için açılan bir alertView vardır. Benzer bir alertView yapma ihtiyacım doğduğunda internette biraz araştırma yaptım. Karşıma çıkan bazı çözümlerin private api kullanımından dolayı Apple tarafından reject edildiğini öğrendim. Fakat şöyle bir çözümün doğru çözüm olduğunu düşünerek şu şekilde istediğimi uyguladım.

- (void) alertViewForPass {
passwordInsertAlert = [[UIAlertView alloc] initWithTitle:@"Sifre" message:@"\n\n\n\n\n" delegate:self cancelButtonTitle:@"Kapat" otherButtonTitles:@"Tamam", nil];
passwordInsertAlert.tag = PASS_INSERT_ALERT_TAG;
currentAlertType = PASS_INSERT_ALERT_TAG;

UILabel *headerLabel = [[UILabel alloc] initWithFrame:CGRectMake(12,40,260,30)];
headerLabel.font = [UIFont systemFontOfSize:13];
headerLabel.textColor = [UIColor whiteColor];
headerLabel.backgroundColor = [UIColor clearColor];
headerLabel.shadowColor = [UIColor blackColor];
headerLabel.shadowOffset = CGSizeMake(0,-1);
headerLabel.textAlignment = UITextAlignmentCenter;
[headerLabel setAdjustsFontSizeToFitWidth:YES];
headerLabel.numberOfLines = 2;
headerLabel.text = @"Sifre Ekrani";
[passwordInsertAlert addSubview:headerLabel];
[headerLabel release];

passInsert1Field = [[UITextField alloc] initWithFrame:CGRectMake(16,83,252,25)];
passInsert1Field.font = [UIFont systemFontOfSize:16];
passInsert1Field.backgroundColor = [UIColor whiteColor];
passInsert1Field.secureTextEntry = YES;
passInsert1Field.keyboardAppearance = UIKeyboardAppearanceAlert;
passInsert1Field.keyboardType = UIKeyboardTypeNumberPad;
passInsert1Field.delegate = self;
passInsert1Field.placeholder = @"Sifre giriniz";
passInsert1Field.tag = PIN_INSERT_FIELD_TAG;
[passInsert1Field becomeFirstResponder];
[passwordInsertAlert addSubview:passInsert1Field];

passInsert2Field = [[UITextField alloc] initWithFrame:CGRectMake(16,120,252,25)];
passInsert2Field.font = [UIFont systemFontOfSize:16];
passInsert2Field.backgroundColor = [UIColor whiteColor];
passInsert2Field.secureTextEntry = YES;
passInsert2Field.keyboardAppearance = UIKeyboardAppearanceAlert;
passInsert2Field.keyboardType = UIKeyboardTypeNumberPad;
passInsert2Field.delegate = self;
passInsert2Field.placeholder = @"Tekrar sifre giriniz";
passInsert2Field.tag = PIN_INSERT_FIELD2_TAG;
[passwordInsertAlert addSubview:passInsert2Field];

[passwordInsertAlert setTransform:CGAffineTransformMakeTranslation(0,109)];
[passwordInsertAlert show];
}

Burada UIAlertView'ı (passwordInsertAlert) instance variable olarak header'da tanımladığımızı varsayalım. Aynı şekilde UITextField'ları (passInsert1Field ve passInsert2Field) da instance variable olarak header'da tanımlıyoruz. Tabi, class'ın dealloc metodu içinde bunları release etmeyi de unutmayalım. Bu arada PIN_INSERT_FIELD_TAG gibi değerler benim #define ile tanımladığım değerler. İsterseniz bu değerler yerine direk unique rakamsal değerler de yazabilirsiniz.

TextField için keyboard ve diğer tuşların yakalanması için class'ımızı UITextFieldDelegate'e extend ediyoruz:

@interface [ClassName] : UIView <UITextFieldDelegate>

Bu arada alertView'dan gelecek aksiyonları handle etmek için de aşağıdaki metodumuzu implement ediyoruz:

- (void) alertView:(UIAlertView *)alert clickedButtonAtIndex:(NSInteger)buttonIndex{
if (alert.tag == PASS_INSERT_ALERT_TAG) {
if (buttonIndex == 1) {
[self hideKeyboard];
[self validateInsert];
}
} else if(alert.tag == PASS_INSERT_ERROR_ALERT_TAG) {
[passwordInsertAlert release];
[self alertViewForPass];
}
}
Burada alertView'lara tanımladığımız tag'lere göre aksiyon alıyoruz. İlk metodumuzda tanımladığımız alertView'ın tag'ı PASS_INSERT_ALERT_TAG olduğunu düşünürsek AlertView'ımızda "Tamam" butonuna basıldığında bu metodda ilk kontrole girecektir. buttonIndex değeri de özellikle değiştirilmediği sürece "Cancel" butonu için 0, "OK" butonu için 1'dir. hideKeyboard metodu extend ettiğimiz UITextFieldDelegate ile gelen ve bizim gerekli durumda extend ettiğimiz bir metod.

UITextFieldDelegate gelen metodları kendime göre kullanmak üzere extend ediyorum.

- (void) showKeyboardAndToolbar {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
if(currentAlertType == PASS_INSERT_ALERT_TAG) {
[passInsert1Field becomeFirstResponder];
}
[pool release];
}

- (void)hideKeyboard {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
if(currentAlertType == PASS_INSERT_ALERT_TAG) {
[passInsert1Field resignFirstResponder];
[passInsert2Field resignFirstResponder];
}
[pool release];
}

- (BOOL) textFieldShouldReturn:(UITextField *)theTextField {
if(currentAlertType == PASS_INSERT_ALERT_TAG) {
if (theTextField.tag == PIN_INSERT_FIELD_TAG) {
[passInsert2Field becomeFirstResponder];
} else {
[self hideKeyboard];
[self validateInsert];
}
}
return YES;
}

validateInsert meted, alert içindeki textField'lara girilen değerleri valide etmek için implement ettiğim bir metod. Siz de burada istediğiniz bir metodu çağırabilirsiniz.
Yine de textField'ların ve alertView tag'larının nasıl handle edildiğini göstermek adına bu metodu da yazayım.

- (void) validateInsert {
if (![passInsert1Field.text isEqual:passInsert2Field.text]) {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Hata"
message:@"Girdiğiniz 2 sifre aynı olmalıdır."
delegate:self
cancelButtonTitle:@"Tamam"
otherButtonTitles:nil];
alertView.tag = PASS_INSERT_ERROR_ALERT_TAG;
[alertView show];
[alertView release];
} else {
//why don't you do something ...
}
}

Burada gördüğümüz gibi hata alert'üne yeni bir tag veriyoruz ki "alertView:(UIAlertView *)alert clickedButtonAtIndex:(NSInteger)buttonIndex" metodu içinde alert'ler karışmasın. Eğer bu metod içine gelen alert'ün tag'i PASS_INSERT_ERROR_ALERT_TAG ise tekrar alertViewForPass metodu tetikleniyor.

Çok basit bir çözüm, ama bir o kadar da hayat kurtarıcı. Son olarak da basit ama gerekli bir bilgi daha ekleyelim. Alert'ler üzerindeki "Tamam" butonunu handle edecek metodlar yazdık fakat bir noktada alert'ü de kapatmamız gerekecektir. Bu durumda şu şekilde alert'ümüzü kapatabiliriz:

[passwordInsertAlert dismissWithClickedButtonIndex:0 animated:YES];
Adeta "Cancel" butonuna basılmış gibi alert'ümü dismiss et diyoruz.

No comments: