iPhone UITableView. Müzik Uygulaması gibi tek harfli alfabetik listeyi nasıl açarım?


82

İPhone müzik uygulamasında, Sanatçı, Şarkılar veya Albümler'i seçmek, kullanıcı arayüzünün sağ tarafında, hızlı kaydırmayı sağlayan tek harflerden oluşan dikey bir liste ile bir tableView sunar. Uygulamamda bu işlevi nasıl etkinleştiririm?

Şerefe, Doug

Yanıtlar:


133

Kendi dizin karakterlerinizi sağlayın:

- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
    return[NSArray arrayWithObjects:@"a", @"e", @"i", @"m", @"p", nil];
}

ve sonra:

- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString
    *)title atIndex:(NSInteger)index {
        return <yourSectionIndexForTheSectionForSectionIndexTitle >;
}

Bölümlere ihtiyacınız olacak.


21
Bölümler olmadan dizinlere sahip olmanın bir yolu var mı (düz bir liste için)?
KULLANIM

12
@ThEuSeFuL Bölüm başlıklarını göstermeden bölümlere sahip olabilirsiniz. Bu, son kullanıcıya düz bir liste gibi görünecektir.
Jon Hull

10
"yourSectionIndexForTheSectionForSectionIndexTitle" ne anlama geliyor?
ravoorinandan

2
@ravoorinandan, aslında başlık dizisindeki başlık değişkeninin dizinini döndürmek anlamına gelir. Dolayısıyla, başlık @ "a" ise, 0 döndürmelidir. Başlık @ "i" ise, 2 döndürmelidir ve böyle devam eder. Bunu, diziyi burada gösterilen her iki yöntem için de kullanılabilir hale getirerek ve ardından ikinci yöntemde [dizi indexOfObject: title] öğesini çağırarak yapabilirsiniz. Bunun altındaki cevabın (UILocalizedIndexedCollation ile ilgili) muhtemelen daha iyi olduğunu söyleyebilirim.
Brian Sachetta

Her ihtimale karşı, herkes benimkiyle aynı hatayı yaptı, film şeridinde tableView'i seçin ve metin rengini istediğiniz renge değiştirin. Benim durumumda, metin rengi otomatik olarak net renk olarak seçildi ve bu nedenle indeks listelenmiyordu. Sorunun ne olduğunu anlamak için epey zaman harcadım.
Vincent Joy

35

Göz önünde bulundurmanız gereken başka bir şey, her dil için bölümleri yerelleştirmek. Biraz kazı yaptıktan sonra, UILocalizedIndexedCollationoldukça faydalı buldum :

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
    return [[[UILocalizedIndexedCollation currentCollation] sectionTitles] objectAtIndex:section];
}

- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
    return [[UILocalizedIndexedCollation currentCollation] sectionIndexTitles];
}

- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index {
    return [[UILocalizedIndexedCollation currentCollation] sectionForSectionIndexTitleAtIndex:index];
}

https://developer.apple.com/documentation/uikit/uilocalizedindexedcollation


34

Bölümleri kullanmadan tek harfli bir alfabe listesini ele almak için alternatif bir yaklaşım buldum. Zaph'ın cevabına benzer, ancak yeni bir dizin döndürmekten herhangi bir değer elde etmek yerine (her zaman 1 bölümümüz olacağından), dizideki ilk öğenin belirli bir karakterle başlayan konumu için dizini hesaplıyoruz, sonra kaydırıyoruz ona.

Bunun dezavantajı, her seferinde diziyi aramayı gerektiriyor (bu kesinlikle korkunç mu?), Ancak iOS simülatöründe veya iPhone 4S'imde herhangi bir gecikme veya yavaş davranış fark etmedim.

- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
  return[NSArray arrayWithObjects:@"A", @"B", @"C", @"D", @"E", @"F", @"G", @"H", @"I", @"J", @"K", @"L", @"M", @"N", @"O", @"P", @"Q", @"R", @"S", @"T", @"U", @"V", @"W", @"X", @"Y", @"Z", nil];
}

- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index {

  NSInteger newRow = [self indexForFirstChar:title inArray:self.yourStringArray];
  NSIndexPath *newIndexPath = [NSIndexPath indexPathForRow:newRow inSection:0];
  [tableView scrollToRowAtIndexPath:newIndexPath atScrollPosition:UITableViewScrollPositionTop animated:NO];

  return index;
}

// Return the index for the location of the first item in an array that begins with a certain character
- (NSInteger)indexForFirstChar:(NSString *)character inArray:(NSArray *)array
{
  NSUInteger count = 0;
  for (NSString *str in array) {
    if ([str hasPrefix:character]) {
      return count;
    }
    count++;
  }
  return 0;
}

gibi son seçilen dizini depolamak için özellik eklemek

 @property (assign, nonatomic) NSInteger previousSearchIndex;

ve bu özelliği her zaman şu şekilde depolamak:

- (NSInteger)indexForFirstChar:(NSString *)character inArray:(NSArray *)array
{
    NSUInteger count = 0;
    for (NSString *str in array) {
        if ([str hasPrefix:character]) {
            self.previousSearchIndex = count;
            return count;
        }
        count++;
    }
    return self.previousSearchIndex;
}

ve aşağıdaki scrollToRowgibi kod güncelleme :

 [tableView scrollToRowAtIndexPath:newIndexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];

Bu yöntemi daha iyi ve güzel bir animasyonla yapın.


14
alfabe dizisini yazmak zorunda olmadığım anlamına geldiği için oy verildi!
Paul Cezanne

1
heh. o da kötü bir çözüm değil ... elma, kod örneğimde bunu kullanarak kakao kampı için beni kabul etti. bunun resmi olarak onayladıkları anlamına gelip gelmediği ... Bilmiyorum;).
Kyle Clegg

@PaulCezanne Aslında, onu daha temiz hale getirmek için, dizelerinizin dizisini gözden geçirmenizi ve tüm dizelerin ilk harflerini almanızı öneririm, böylece listeniz dinamik olur, böylece herhangi bir öğeniz yoksa Q'larınız olmaz. Q harfiyle başlayın. Bunu göstermek için kodumu güncellememi isterseniz bana bildirin.
Kyle Clegg

Teşekkürler. Aslında bunu üzerinde çalıştığım başka bir uygulamada yaptım. Pratikte oldukça tuhaf görünüyordu. Yan taraftaki AZ dizisi oldukça açıklayıcı. Yalnızca az sayıda şarkınız varsa veya çok fazla filtre uyguladıysanız sahip olacağınız birkaç harfiniz olduğunda, yan taraftaki harflerin amacı tuhaf görünür.
Paul Cezanne

1
@Mingebag Her çağrıldığında indexForFirstChar'ın dönüş değerinin ne olduğunu kontrol ederek hata ayıklamayı deneyin. Her seferinde 0 ile 25 arasında olmalıdır. 25'ten büyükse, belki alfabetik olmayan karakterler veya çok yüksek bir değer döndürmesine neden olan başka bir şeyiniz vardır.
Kyle Clegg

21

Bir grup insan bunu bölümler olmadan yapmanın mümkün olup olmadığını sordu. Ben de aynı şeyi istedim ve biraz gölgeli olabilecek ve sectionForSectionIndexTitle için bir değer döndürmeyen bir çözüm buldum, ancak bir köşedeyseniz ve alfabenin her harfi için bir bölüm yapmak zorunda kalmak istemiyorsanız bu kesin bir düzeltmedir. Nazileri önceden kodladığım için özür dilerim. : P

- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
    if (thisTableDataIsShowing)
    {
        NSMutableArray *charactersForSort = [[NSMutableArray alloc] init];
        for (NSDictionary *item in d_itemsInTable)
        {
            if (![charactersForSort containsObject:[[item valueForKey:@"character_field_to_sort_by"] substringToIndex:1]])
            {
                [charactersForSort addObject:[[item valueForKey:@"character_field_to_sort_by"] substringToIndex:1]];
            }
        }
        return charactersForSort;
    }
    return nil;
}

- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index {
    BOOL found = NO;
    NSInteger b = 0;
    for (NSDictionary *item in d_itemsInTable)
    {
        if ([[[item valueForKey:@"character_field_to_sort_by"] substringToIndex:1] isEqualToString:title])
            if (!found)
            {
                [d_yourTableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:b inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:NO];
                found = YES;
            }
        b++;
    }
}

Büyük miktarda veri alıyorsanız ve bölümlere ayırıyorsanız harika çalışıyor. :) Genel değişkenleri kullanmaya çalıştım, böylece ne yaptığımı biliyordun. d_itemsInTable, UITableView'da listelediğim NSDictionaries NSDictionaries Dizisidir.


1
Eğlenceli faks: -1 döndürürseniz, derleyici uyarılarını göz ardı eder ve sectionForSectionIndexTitle yönteminden o bölüme kaydırmaya çalışmaz
elimirks

Gerçekten harika bir örnek, teşekkürler tahsisat belki fondan sonra bir fren ekleyerek = EVET; o kadar da kötü olmaz ^^
Mingebag

3

Aşağıda, bir dizesi olmayan bir dizine tıklama durumunu işleyen Kyle'ın işlevinin değiştirilmiş bir sürümü bulunmaktadır:

- (NSInteger)indexForFirstChar:(NSString *)character inArray:(NSArray *)array
{
    char testChar = [character characterAtIndex:0];
    __block int retIdx = 0;
    __block int lastIdx = 0;

    [array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
        char firstChar = [obj characterAtIndex:0];

        if (testChar == firstChar) {
            retIdx = idx;
            *stop = YES;
        }

        //if we overshot the target, just use whatever previous one was
        if (testChar < firstChar) {
            retIdx = lastIdx;
            *stop = YES;
        }

        lastIdx = idx;
    }];
    return retIdx;
}

3

A kullanıyorsanız NSFetchedResultsController, şunları yapabilirsiniz:

- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
    return [frc sectionIndexTitles];
}

- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index {
    return [frc sectionForSectionIndexTitle:title atIndex:index];
}


2

Başlık başlıklarınızın bir dizide bulunduğunu varsayarsak Swift için basit bir çözüm. Başlık bulunamazsa, dizideki önceki dizini döndürür.

func sectionIndexTitlesForTableView(tableView: UITableView) -> [String]? {
    return "ABCDEFGHIJKLMNOPQRSTUVWXYZ".characters.flatMap{String($0)}
}

func tableView(tableView: UITableView, sectionForSectionIndexTitle title: String, atIndex index: Int) -> Int {
    return self.headerTitles.filter{$0 <= title}.count - 1
}

İkinci dönüş satırının return self.headerTitles.count - self.headerTitles.filter{$0 > title}.count, verilen dizin başlığı için son eşleşen bölümden ziyade ilkinin dizinini döndürmek için değiştirilmesinin tercih edildiğini düşünüyorum .
Chris C

Müşterinin gerçekten ne beklediğine bağlı. Muhtemelen, hangi işlevselliği seçerseniz seçin, istediklerinin tam tersi olacaktır. :)
Samah

0

MonoTouch kullanıyorsanız, UITableViewDataSource sınıfındaki SectionIndexTitles (UITableView) yöntemini geçersiz kılın. Sadece bir dizi döndürürseniz alt sınıf gerisini halleder.

class TableViewDataSource : UITableViewDataSource
{
  public override string[] SectionIndexTitles(UITableView tableView) 
  { 
    return new string[] { /*your string values */};
  }
}

* iPhone uygulamaları yazmak için C # ve Mono (.NET) kullananlarımız için sadece bir ipucu. :)

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.