iPhone UITableView。如何打开音乐应用程序之类的单字母字母列表?


82

在iPhone音乐应用程序中,选择“艺术家”,“歌曲”或“专辑”将在UI的右侧显示一个tableView,其中包含单个字母的垂直列表,从而可以快速滚动。如何在我的应用程序中启用此功能?

干杯,道格

Answers:


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”是什么意思?
ravoorinandan13年

2
@ravoorinandan他实际上意味着返回您的titles数组中title变量的索引。因此,如果标题为@“ a”,则应返回0。如果标题为@“ i”,则应返回2,依此类推。您可以通过使数组可用于此处显示的两个方法,然后在第二个方法中调用[array indexOfObject:title]来实现此目的。虽然我会说下面的答案(与UILocalizedIndexedCollat​​ion有关)可能更好。
Brian Sachetta 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

我想出了另一种方法来处理单个字母的字母列表而不使用部分。它与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];

使用更好的动画效果更好地执行此方法。


14
仅仅因为它意味着我不必键入字母数组而被投票!
保罗·塞尚

1
呵呵。这也不是一个不好的解决方案...苹果公司在我的代码示例中使用了这个,使我接受了可可营地的服务。那是否意味着他们正式认可它...我不知道;)。
凯尔·克莱格

@PaulCezanne实际上,为使它更整洁,我建议您遍历字符串数组并获取所有字符串的upperCase首字母,以便您的列表具有动态性,因为如果没有任何项目,则不会有任何Q。以字母Q开头。如果您希望我更新代码以显示此信息,请告诉我。
凯尔·克莱格2013年

谢谢。我实际上是在我正在开发的另一个应用程序中做到的。实际上看起来很奇怪。侧面的AZ阵列很好解释。当您只有几个字母时(如果您只听少量歌曲或经过大量过滤,就会拥有字母),旁边的字母的目的看起来很奇怪。
Paul Cezanne 2013年

1
@Mingebag尝试通过检查每次调用indexForFirstChar的返回值来对其进行调试。每次应在0到25之间。如果它大于25,则可能是因为您使用非字母字符或其他原因导致其返回的值太高。
凯尔·克莱格

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是NSDictionaries的NSArray,我将其列出到UITableView中。


1
有趣的传真:如果返回-1,它将忽略编译器警告,而不尝试从
sectionForSectionIndexTitle

真的很棒,感谢资金分配,也许在基金= YES之后增加了刹车;也不会那么糟糕^^
Mingebag

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返回给定索引标题的第一个而不是最后一个匹配节的索引。
克里斯·C

确实取决于客户的期望。无论您选择哪种功能,都可能与他们想要的相反。:)
Samah

0

如果使用的是MonoTouch,请重写UITableViewDataSource类中的SectionIndexTitles(UITableView)方法。只需返回一个字符串数组,子类将负责其余的工作。

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

*仅向使用C#和Mono(.NET)编写iPhone应用程序的人提供提示。:)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.