MAR
25

iPhone SDK ile UIScrollView Kullanarak Home Screen Benzeri Sayfalama

4 yorum | Kategori: Mobil Programlama | 25 Mart 2011 Cuma

Daha önceki bir yazımda ScrollView bileşeninin nasıl kullanıldığını anlatmış ve gelecekteki bir yazımda bu bileşen yardımıyla iOS ana ekranındaki (home screen) sayfalama işlevseliğinin aynısının nasıl yapılacağını anlatacağımı söylemiştim. Bu yazımda ele alacağım konu tam olarak bu. Her zamanki gibi örnek bir iphone uygulaması yazacağım ancak daha önceki yazımda yazılan şeylerin artık bilindiğini varsayıp orada anlatmış olduğum şeyleri tekrar etmeyeceğim. Örnek uygulamanın her biri basit bir UILabel bileşeni içeren toplam 3 sayfası olacak. Ancak bu sayfalar farklı ViewController'lar tarafından kontrol edilen farklı ekranlarda olmayacak. Tek bir ViewController tarafından kontrol edilen, tek bir ekranda olacak. ScrollView yardımıyla bu tek ekran sanki 3 sayfaymış gibi gösterilecek. Kullanıcıya kaçıncı sayfada olduğu, UIPageControl nesnesinin arayüze koyduğu dairelerle (aynı Home screen'de olduğu gibi) gösterilecek.

Öncelikle View-Based Application taslağını kullanarak yeni bir proje yaratın. Ben projenin adını "Sayfalama" koydum ve dosya isimlerim de ona göre olacak. Bu projede arayüze editörü kullanarak sadece bir UIScrollView ve bir de UIPageControl nesnesi koymak yeterli. Bunu yapmadan önce "SayfalamaViewController.h" adlı Objective-C header dosyasında bu iki nesne için birer Outlet tanımlayın. Sonra bu ViewController ScrollView'ın delegate'i olacağından, UIScrollViewDelegate protokülünü desteklemesi için gereken satırı ekleyin. Bunlara ek olarak ne için kullanacağınızı az sonra söyleyeceğim "sayfaDegistir:" adlı bir metod ve "pageControlKullanildi" adında ve BOOL tipinde bir özellik tanımlayın de. Tüm bu işlemlerden sonra .h dosyasının içi şu hale gelmiş olmalı.

#import <UIKit/UIKit.h>

@interface SayfalamaViewController : UIViewController
<UIScrollViewDelegate>
{
    BOOL pageControlKullanildi;
}

@property (nonatomic,retain) IBOutlet UIScrollView *scroller;
@property (nonatomic,retain) IBOutlet UIPageControl *pageControl;

- (IBAction)sayfaDegistir:(id)sender;

@end

Sonra "SayfalamaViewController.m" adlı Objective-C kod dosyasına gerekli @synthesize direktiflerini ve bellek iade satırlarını ekleyerek şu hale getirin.

#import "SayfalamaViewController.h"

#define SAYFA_SAYISI 3

@implementation SayfalamaViewController

@synthesize scroller, pageControl;

- (void)viewDidUnload
{
    [super viewDidUnload];
    self.scroller = nil;
    self.pageControl = nil;
}

- (void)dealloc
{
    [scroller release];
    [pageControl release];
    [super dealloc];
}

Burada söylediklerime ek olarak, bir de SAYFA_SAYISI adında bir tanımlama yaptım. Bu uygulamanın kaç sayfa içereceğini gösteren bir tanımlama. Az sonra sayfalama işlevini yazarken bu tanımlamayı bir kaç kez kullanacaksınız. Böyle ayrı bir tanımlama yapmış olmamın sebebi uygulamanın sayfa sayısını deneme yapabilmek amacıyla kolayca değiştirebilmenizi sağlamaktan öte bir şey değil.

Şimdi "SayfalamaViewController.xib" adlı arayüz dosyasını açıp içerisine bir adet UIScrollView ve bir adet de UIPageControl nesnesi yerleştirerek aşağıdaki hale getirin.

iPhone UIScrollView ve UIPageControl ile Sayfalama Örnek Arayüzü

Şimdi her iki bileşen için de Outlet bağlantılarını yapın ve ScrollView'in delegate'i olarak da SayfalamaViewController sınıfını ayarlayın. Sonra ScrollView'in Paging Enabled özelliğini açıp, yatay ve dikey kaydırma çubuklarını gösterme ayarlarını kapatın. Paging Enabled özelliği, ScrollView kendi genişliğinin tam katı olan miktarlarda, yani yeni bir sayfaya geçilecek kadar kaydırıldığında, kaydırma işleminin sonlanmasını sağlıyor. Kaydırma çubuklarını ise gereksiz oldukları için kapattık. Son olarak pageControl nesnesinin Value Changed event'ini, daha önce tanımlamış olduğunuz sayfaDegistir: metoduna bağlayın. Bunu yaptıktan sonra pageControl nesnesinin sol veya sağ tarafına tıkladığınızda bu metod çağrılacak ve sayfa düzgün bir şekilde değişecek.

Sıradaki işiniz, ScrollView içerisinde gösterilecek sayfaları hazırlamak. Bunun için viewDidLoad: metodu en uygun yer. Bu metodu aşağıdaki hale getirin:

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Kayar panelin içerik boyutunu SAYFA_SAYISI kadar sayfayı alabilecek boyuta getir
    scroller.contentSize = CGSizeMake(scroller.frame.size.width * SAYFA_SAYISI, scroller.frame.size.height);
    
    // Her sayfanın içerisine, sayfa numarasını gösteren bir UILabel koy
    for (int i=0; i<sayfa_sayisi; i++)
    {
        UILabel* label = [[[UILabel alloc] init] autorelease];
        
        label.text = [NSString stringWithFormat:@"%d. Sayfa",i+1];
        label.font = [UIFont fontWithName:@"Helvetica" size:30];
        label.backgroundColor = [UIColor clearColor];
        
        // Label'ı ilgili sayfaya koy
        label.frame = CGRectMake(scroller.frame.size.width * i + 100, 200, 200, 50);
       
        // Label'ı kayar panele ekle
        [scroller addSubview:label];
    }
    
    // pageControl nesnesinin özelliklerini ayarla ve ilk sayfada başladığımızdan emin ol
    pageControl.numberOfPages = SAYFA_SAYISI;
    pageControl.currentPage = 0;
    [self sayfaDegistir:nil];
}

Burada ScrollView'in içerisine sayfa sayısı kadar UILabel nesnesi koyduk. Burada dikkat edilmesi gereken noktalar; ScrollView'in içerik boyutunun tam SAYFA_SAYISI tane ScrollView genişliği kadar yapılması, her Label'ın x koordinatının ilgili sayfanın başladığı x koordinatına göre verilmesi ve pageControl nesnesine sayfalama işlemini düzgün yapabilmesi için ihtiyacı olan değerlerin atanması. Şimdi sıra geldi asıl işi yapan metod olan sayfaDegistir: metoduna.

- (IBAction)sayfaDegistir:(id)sender
{
    int sayfa = pageControl.currentPage;
    
    // Kayar paneli ilgili sayfaya kaydır
    CGRect frame = scroller.frame;
    frame.origin.x = frame.size.width * sayfa;
    frame.origin.y = 0;
    [scroller scrollRectToVisible:frame animated:YES];
    
    // Kaydırma işleminin UIPageControl nesnesi tarafından başlatıldığını belirten bayrağı 1 yap
    pageControlKullanildi = YES;
}

Bu metod pageControl nesnesinin sol veya sağ kısmına basılarak sayfa değiştirilmeye kalkıldığında çağrıldığını biliyoruz. Öncelikle hangi sayfaya gidileceğini pageControl nesnesinden öğrendik. Sonra ScrollView'in içeriğini ilgili sayfayı tam olarak görünür yapacak şekilde yatay eksende kaydırdık. Son satırdaki bayrağı YES yapmamızın sebebi, kaydırma işleminin pageControl nesnesi tarafından başlatıldığı bilgisini kaydetmek. Bu bilgiye neden ihtiyaç duyduğumuzu az sonra göreceksiniz.

Uygulamayı bu haliyle çalıştırırsanız ekranın alt kısmındaki pageControl bileşenini kullanarak sayfalar arasında geçiş yapabildiğinizi görürsünüz. Ancak eğer sayfa çevirme işleminin aynı iOS Home Screen'de olduğu gibi yukarıdaki ScrollView'i kaydırarak da yapılabilmesiniz isterseniz, UIScrollViewDelegate protokolünde bulunan bazı metodların aşağıdaki şekilde implementasyonunu yapmanız gerekli.

- (void)scrollViewDidScroll:(UIScrollView *)sender
{
    // Eğer sayfa çevirme işlemi kullanıcının paneli kaydırması ile değil, pageControl nesnesi ile yapılmışsa hiçbir şey yapma
    if (pageControlKullanildi) return;
    
    // Önceki yada sonraki sayfanın yarısından fazlası görünür hale gelmişse pageControl nesnesinin sayfa göstergesini güncelle
    float pageWidth = scroller.frame.size.width;
    int page = floor((scroller.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
    pageControl.currentPage = page;   
}

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
    pageControlKullanildi = NO;
}

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
    pageControlKullanildi = NO;
}

İşte burada pageControlKullanildi bayrağının ne işe yaradığını görüyorsunuz. Eğer kaydırma işlemini pageControl nesnesi başlatmışsa, scollViewDidScroll: metodunda hiçbir şey yapmıyoruz. Çünkü bu metodun içerisinde pageControl nesnesinin sayfa göstergesini güncellenmekte. Eğer pageControl nesnesinin başlatmış olduğu bir kaydırma işlemi sırasında tekrar pageControl nesnesinin değerini güncellersek, tekrar sayfaDegistir: metodu çağrılacak, dolayısıyla tekrar bir kayma işlemi başlatılacak ve bunun üzerine çağrılacak olan scollViewDidScroll: metodunda da tekrar pageControl nesnesinin değeri değişecek. Yani uygulama anlamsız bir kısır döngü içerisine girmiş olacak. İşte o bayrağı bunu engellemek için kullanıyoruz. Kullanıcının kaydırma işlemini kendisi başlattığı ve bıraktığı zamanlarda çağrılacak olan diğer iki delegate metodunda da bayrağı sıfırlıyoruz çünkü artık kaydırma işlemi kullanıcı tarafından yapılmış oluyor, pageControl nesnesi tarafından değil.

Uygulamayı bu son değişiklikle birlikte tamamlamış olduğunuz. Şimdi çalıştırırasanız hem scrollView'i parmağınızla kaydırarak, hem de pageControl nesnesinin sol veya sağ kısmına dokunarak sayfa değiştirebildiğinizi göreceksiniz. Aşağıda uygulamanın son halinden 2 ekran görüntüsü veriyorum. İlki uygulama ilk açıldığındaki halini, diğeri ise sayfa çevrilirkenki halini gösteriyor.

iPhone'da UIScrollView ve UIPageControl ile Sayfalama Örneği Son Hali 1
   iPhone'da UIScrollView ve UIPageControl ile Sayfalama Örneği Son Hali

Yorumlar

Bu yazı hakkında toplam 4 yorum bulunmaktadır. Siz de yorum ekleyebilirsiniz.
Yorum Cihan Tek | 12 Ağustos 2011 Cuma 22:18:46
Aynı anda 5'ten fazla resmi bellekte tutmak gereksiz bellek katliamı olur. Kaydırma hızına göre herhangi bir sayfaya geçildiğinde onun sağ ve solundaki birer veya ikişer sayfaya ait olan resimleri yükleyip ilgili offsetlere koyarak yapabilirsiniz istediğinizi. Bu da zaten sizin demiş olduğunuz şeye denk geliyor ve gayet basit bir çözüm.

ScrollView'ın content size'ının içi boş olduğu sürece ne kadar büyük olduğunun hiçbir önemi yok performans ve bellek kullanımı açısından. Toplamda kaç resim gösterecekseniz o kadar geniş yapabilirsiniz.
Yorum ali koç | 12 Ağustos 2011 Cuma 22:09:33
tşkler bir sorum daha olacak umarım bununda çözümü kolaydır. resim galerisi yapıyorum 2000 civarı resim var hepsiini birden scrolview'in içine yüklemiyor kapanıyor program. bende 50 şerli gruplar halinde listelemek istedim ama ondada takılmalar oluyor ileriki sayfalara geçince. şimdi sadece 3 tane imageview koymak istiyorum scrol'un içine ve kullanıcı her ileri veya geri gittiğinde resimlerin yerini değişip ofsetlicek scrolu. böylece programın takılmamasını ümid ediyorum. bundan daha sağlıklı basit bi çözüm yolu varmı acaba. baya bi araştırdım nette ama birşey bulamadım malumunuz kaynakların heps ing :(
şimdiden tşkler
Yorum Cihan Tek | 09 Ağustos 2011 Salı 20:58:39
Her sayfanın genişiliğini ekran genişliğinden biraz daha küçük yapmanız ve bunları ScrollView içerisine koyarken her iki tarafta eşit miktarda boşluk olacak şekilde offset değerleri kullanmanız gerekiyor. Eğer önceki ve sonraki sayfaların uçlarının da görülmesini istiyorsanız bir kağıt üzerinde 3 tane örnek sayfa çizip offset değerlerinin nasıl hesaplanacağını görebilirsiniz.
Yorum ali koç | 09 Ağustos 2011 Salı 20:03:18
slm
öncelikle başarılı bi anlatım olmuş emeğinize sağlık.
bi sorum olacak sayfalar arası geçiş sırasında iki sayfa arası boşluk kalması için ne yapmalıyız. tamamen estetik amaçlı. iphone'nin kendi resim galerisinde olduğu gibi..

Yorum Yazın

İsim ve soyadınız : E-Posta adresiniz : Güvenlik kodu : Güvenlik Kodu Yorumunuz : Gönder