为A到Z UITableView滚动添加节索引标题

4

我想要为联系人表视图添加一些部分标题。我有一个联系人列表,可能像这样:Array

Bill Apple
Borat
Steve Test

我已经添加了以下内容:

func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
    let currentCollation = UILocalizedIndexedCollation.currentCollation() as UILocalizedIndexedCollation
    let sectionTitles = currentCollation.sectionTitles as NSArray
    return sectionTitles.objectAtIndex(section) as? String
}

func sectionIndexTitlesForTableView(tableView: UITableView) -> [String]? {
    let currentCollation = UILocalizedIndexedCollation.currentCollation() as UILocalizedIndexedCollation
    return currentCollation.sectionIndexTitles as [String]
}

func tableView(tableView: UITableView, sectionForSectionIndexTitle title: String, atIndex index: Int) -> Int {
    let currentCollation = UILocalizedIndexedCollation.currentCollation() as UILocalizedIndexedCollation
    return currentCollation.sectionForSectionIndexTitleAtIndex(index)
}

这将显示A-Z标题。然而,由于只有一个部分和一个数组存储联系人,实际功能无法正常工作。
我们应该将Array按字母顺序排序为字母顺序Array吗?以便它具有多个部分?还是有更简单的方法来解决这个问题?
3个回答

6
我们是否应该对数组进行按字母排序,以便它有多个部分?
是的。
你添加了用于索引标题的委托方法,但你没有展示任何实际执行整理的代码。
以下是来自NSHipster的一些示例代码,显示如何使用UILocalizedIndexedCollation将对象数组(例如联系人)整理成对象的节数组(例如按节分组的联系人): 点击此处查看示例代码
let collation = UILocalizedIndexedCollation.currentCollation()
var sections: [[AnyObject]] = []
var objects: [AnyObject] = [] {
    didSet {
        let selector: Selector = "localizedTitle"
        sections = Array(count: collation.sectionTitles.count, repeatedValue: [])

        let sortedObjects = collation.sortedArrayFromArray(objects, collationStringSelector: selector)
        for object in sortedObjects {
            let sectionNumber = collation.sectionForObject(object, collationStringSelector: selector)
            sections[sectionNumber].append(object)
        }

        self.tableView.reloadData()
    }
}

您还需要更新剩余的tableView代理以使用sections数组:

override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
    return sections.count
}

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return sections[section].count
}

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let contact = sections[indexPath.section][indexPath.row]
    ...
} 

您可以通过将排序属性分配给视图控制器来简化委托代码,而不是在每个委托方法中重复声明一个局部变量来表示(当前的)排序。例如:

override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String {
    return collation.sectionTitles[section]
}

我也是这么想的。非常感谢你提供如此有用的信息。 - StuartM

1

如果您按照显示的方式组织结构准备数据,那么tableview非常容易处理。

正如您所知,您在委托中不会收到部分标题,而是IndexPath。因此,最方便的方法是将数据重组为IndexPath可访问。

  • 将数据列表保存在后备存储器中,不直接用于表视图。这对于在线应用程序来说要么在服务器上,对于离线应用程序来说则是在受控数据中,如果数据不太大,则保存在内存中。后备存储器针对搜索和过滤进行了优化。
  • 为各个部分创建一个NSArray<DataNode*>。将数组按照表格的顺序排序。
  • 在每个中,您有元数据,例如部分标题、折叠信息等,以及实际数据,例如部分头节点(如果有)和作为地址的NSArray<DataNode*>的子级。再次按您想要的方式排序。

现在,所有委托函数都变得非常简单,或多或少地减少到

tableData.count  // count of sections
tableData[indexPath.section] // section header data
tableData[indexPath.section].children.count // rows in section
tableData[indexPath.section].children[indexPath.row]  // row data

如果您有一个“实时过滤器”函数,用户键入一些字符并且您想将列表减少到匹配项,则实际上需要从原始数据列表重新构建DataNode列表。
-(void) buildSearchresult:(NSString *)criteria {
    NSArray *result = [backingListService findWithCriteria:criteria];
    NSArray *nodes = [displayListService structureResult:result withOption:OPTAlphaSort];
    [[NotificationCenter defaultCenter] postNotification:@"listUpdate" object:nodes];
}

在后台运行搜索和数据重组,并使用NotificationCenter将新列表发送给代理。
代理将捕获更新的列表并将其放置在[self.tableView reloadData]的位置:
-(void)onUpdateListData:(NSNotification *)mesg {
    NSArray *nodes = mesg.object;

    self.displayData = nodes;
    [self.tableView reloadData];
}  

这就是我如何做到的 :-)

0

嗨@StuartM,这里有一个Objective-C的例子,你可以用Swift重新编写。我发布它是因为这个算法很好用。正如您所看到的,算法在UITableView的代理方法numberOfsectionsInTableView中被调用,因此由于索引和部分数量取决于数组的内容,每次都会重新计算索引。

#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    // Create sections from raw list of all objects
    return [self numberOfsectionForObjectsList];
}


- (NSInteger)numberOfsectionForObjectsList
{

    NSMutableArray *tempAllObjects = [[NSMutableArray alloc] init];
    NSMutableArray *tempDigitsSection = nil;
    NSMutableArray *tempLetterSection = nil;
    NSMutableArray *tempIndex = [[NSMutableArray alloc] init];
    BOOL digitIndexCreated = NO;
    NSString *currentLetter = nil;

    for (id *object in allObjectsList)
    {
        if ([object login].length > 0)
        {
            NSString *firstLetter = [[object login] substringToIndex:1];
            NSCharacterSet *notDigits = [[NSCharacterSet decimalDigitCharacterSet] invertedSet];
            if ([firstLetter rangeOfCharacterFromSet:notDigits].location == NSNotFound) // firstLetter is a digit, not a letter
            {
                if (digitIndexCreated == NO)
                {
                    [tempIndex insertObject:@"#" atIndex:0];
                    tempDigitsSection = [[NSMutableArray alloc] init];
                    digitIndexCreated = YES;
                }

                [tempDigitsSection addObject:object];
            }
            else // firstLetter is a letter, not a digit
            {
                if ([firstLetter caseInsensitiveCompare:currentLetter] == NSOrderedSame) // Always the same first letter = same section
                {
                    [tempLetterSection addObject:object];
                }
                else // New first letter = new section
                {
                    if (tempLetterSection == nil)
                    {
                        tempLetterSection = [[NSMutableArray alloc] init];
                        [tempIndex addObject:[firstLetter uppercaseString]];
                    }
                    else
                    {
                        [tempAllObjects addObject:[tempLetterSection copy]];
                        [tempIndex addObject:[firstLetter uppercaseString]];
                        tempLetterSection = nil;
                        tempLetterSection = [[NSMutableArray alloc] init];
                    }

                    [tempLetterSection addObject:object];
                    currentLetter = firstLetter;
                }
            }
        }
    }

    if (tempDigitsSection != nil)
    {
        [tempAllObjects insertObject:tempDigitsSection atIndex:0];
    }
    if (tempLetterSection != nil)
    {
        [tempAllObjects addObject:tempLetterSection];
    }

    indexesList = [tempIndex copy];
    allObjectsList = nil;
    allObjectsList = [tempAllObjects copy];

    if ([allObjectsList count] > 0)
    {
        return [allObjectsList count];
    }
    else
    {
        return 1;
    }
}

希望这可以帮到你,即使它可以被优化 ^^


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接