web-dev-qa-db-ja.com

iPhone UITableView。ミュージックアプリのような1文字のアルファベット順のリストを有効にする方法は?

IPhoneの音楽アプリで、アーティスト、曲、またはアルバムを選択すると、UIの右側に1文字の縦書きリストを含むtableViewが表示され、高速スクロールが可能になります。アプリでこの機能を有効にするにはどうすればよいですか?

乾杯、ダグ

81
dugla

独自のインデックス文字を指定します:

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

その後:

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

セクションが必要になります。

135
zaph

他に考慮しなければならないことは、各言語のセクションをローカライズすることです。少し掘り下げた後、UILocalizedIndexedCollationが非常に役立つことがわかりました。

- (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/uilocalizedindexedcollat​​ion

35
rwyland

セクションを使用せずに1文字のアルファベットのリストを処理する代替方法を思いつきました。 Zaphの答えに似ていますが、新しいインデックスを返すことから値を取得する代わりに(常に1つのセクションがあるため)、特定の文字で始まる配列の最初のアイテムの位置のインデックスを計算し、スクロールしますそれに。

欠点は、毎回アレイを検索する必要があることです(これは絶対にひどいですか?)が、iOSシミュレーターまたはiPhone 4Sで遅延またはスロー動作に気付かなかった。

- (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;
}

最後に選択したインデックスを保存するプロパティを追加する

 @property (assign, nonatomic) NSInteger previousSearchIndex;

そして、このプロパティを次のように毎回保存します。

- (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;
}

およびscrollToRowコードの更新:

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

この方法は、ニースアニメーションを使用してさらに改善します。

33
Kyle Clegg

多くの人々が、セクションなしでこれを行うことができるかどうかを尋ねました。私は同じものが欲しかったので、少し日陰になり、sectionForSectionIndexTitleに値を返さないソリューションを見つけましたが、コーナーにいて、アルファベットのすべての文字のセクションを作成する必要がない場合は、確実な修正です。事前にコードナチスに申し訳ありません。 :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++;
    }
}

大量のデータを取得し、セクショニングに多くの作業が必要な場合に最適です。 :)汎用変数を使用してみたので、あなたは私が何をしていたかを知っていました。 d_itemsInTableは、UITableViewにリストしているNSDictionariesのNSArrayです。

21
krut

NSFetchedResultsControllerを使用している場合は、次のことができます。

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

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

文字列を持たないインデックスをクリックする場合を処理する、Kyleの関数の修正版は次のとおりです。

- (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
Danny

配列にタイトルヘッダーがあると仮定した場合のSwiftの簡単なソリューションを次に示します。タイトルが見つからなかった場合、配列内の前のインデックスを返します。

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
}
2
Samah

デリゲートメソッドを実装する-sectionIndexTitlesForTableView:および-tableView:sectionForSectionIndexTitle:atIndex:

詳細については、 UITableViewDataSource のドキュメントを参照してください。

2
Alex Reynolds

MonoTouchを使用している場合、UITableViewDataSourceクラスのSectionIndexTitles(UITableView)メソッドをオーバーライドします。文字列の配列を返すだけで、サブクラスが残りを処理します。

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

* C#とMono(.NET)を使用してiPhoneアプリを作成するユーザー向けのヒントです。 :)

0
benhorgen