iPhoneUITableView。ミュージックアプリのような1文字のアルファベット順のリストをオンにするにはどうすればよいですか?


82

iPhoneミュージックアプリで、Artist、Songs、またはAlbumsを選択すると、UIの右側に1文字の垂直リストが表示され、高速スクロールが可能になります。アプリでこの機能を有効にするにはどうすればよいですか?

乾杯、ダグ

回答:


133

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

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

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


21
セクションなしでインデックスを作成する方法はありますか(フラットリストの場合)?
これらの使用法2011

12
@ThEuSeFuLセクションヘッダーを表示せずにセクションを作成できます。これは、エンドユーザーにはフラットリストのように見えます。
ジョンハル

10
「yourSectionIndexForTheSectionForSectionIndexTitle」とはどういう意味ですか?
ravoorinandan 2013年

2
@ravoorinandan彼は基本的に、titles配列のtitle変数のインデックスを返すことを意味します。したがって、タイトルが@ "a"の場合、0を返す必要があります。タイトルが@ "i"の場合、2を返す必要があります。これを行うには、ここに示す両方のメソッドで配列を使用できるようにしてから、2番目のメソッドで[array indexOfObject:title]を呼び出します。これより下の答え(UILocalizedIndexedCollat​​ionに関連する)の​​方がおそらく良いと思いますが。
ブライアンサケッタ2015

万が一に備えて、誰かが私のと同じ間違いをした場合は、ストーリーボードでtableViewを選択し、テキストの色を希望の色に変更してください。私の場合、テキストの色は自動的にクリアカラーとして選択されたため、インデックスは表示されませんでした。私は何が問題なのかを理解するのにかなりの時間を無駄にしました。
ヴィンセントジョイ

35

あなたが考慮しなければならない他の何かは、各言語のセクションをローカライズすることです。少し掘り下げた後、私は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


34

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

欠点は、毎回配列を検索する必要があることです(これは絶対にひどいですか?)が、iOSシミュレーターまたはiPhone4Sでの遅延や遅い動作には気づきませんでした。

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

この方法をさらに上手く、素敵なアニメーションで実行してください。


14
アルファベットの配列を入力する必要がなかったという理由だけで賛成です!
ポール・セザンヌ2013年

1
ふふ。それも悪い解決策ではありません...アップルは私のコードサンプルでこれを使用してココアキャンプに私を受け入れました。それが彼らがそれを公式に承認することを意味するかどうか...私は知りません;)。
カイルクレッグ2013年

@PaulCezanne実際、よりクリーンにするために、文字列の配列をループして、すべての文字列の大文字の最初の文字を取得することをお勧めします。これにより、リストが動的になり、次のような項目がない場合はQが表示されなくなります。文字Qで始まります。これを表示するようにコードを更新するかどうかをお知らせください。
カイルクレッグ2013

ありがとう。私は実際に私が取り組んでいた別のアプリでそれをしました。実際にはかなり奇妙に見えました。側面のAZ配列はかなり説明的です。文字数が少ない場合(曲数が少ない場合やフィルタリングが多い場合)、横にある文字の目的は奇妙に見えます。
ポール・セザンヌ2013

1
@Mingebag呼び出されるたびに、indexForFirstCharの戻り値を確認してデバッグしてみてください。毎回0から25の間でなければなりません。25を超える場合は、アルファベット以外の文字などが原因で、高すぎる値が返される可能性があります。
カイルクレッグ2013

21

多くの人々が、セクションなしでこれを行うことが可能かどうか尋ねました。私は同じことを望み、少し怪しげで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です。


1
楽しいファックス:-1を返すと、コンパイラの警告が無視され、sectionForSectionIndexTitleメソッドからそのセクションにスクロールしようとはしません
elimirks 2013

本当に素晴らしいサンプルのおかげで、fund = YESの後にブレーキを追加することができます。また、それほど悪くはないでしょう^^
Mingebag 2013

3

文字列がないインデックスをクリックした場合を処理する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

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

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

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


2

タイトルヘッダーが配列にあると仮定した場合の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
}

return self.headerTitles.count - self.headerTitles.filter{$0 > title}.count指定されたインデックスタイトルの最後の一致セクションではなく、最初のインデックスを返すように2番目の戻り行を変更することが望ましいと思います。
クリスC

本当に、クライアントが何を期待しているかに依存します。どちらの機能を選択しても、必要な機能とは逆になる可能性があります。:)
サマ2017年

0

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

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

* C#とMono(.NET)を使用してiPhoneアプリを作成している私たちへのヒントです。:)

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.