美文网首页iOS平时生活和工作中的iOSUI基础
实现通讯录分组排序的一个方法

实现通讯录分组排序的一个方法

作者: _奔跑的炸鸡 | 来源:发表于2016-04-12 17:53 被阅读2018次

    在APP开发中,我们经常会去做一个通讯录。所有做iOS开发的都知道这玩意儿应该用UITableView来做。但是,如何将数据分组排序总是一个比较麻烦的问题,这里提供我个人的解决方法供大家参考。


    排序的目标

    因为要是用UITableView,所以我们的数据源应该是这样一个数组:数组dataArray拥有27个子数组subArray,前26个subArray存储以A到Z开头的联系人,第27个数组存储不以字母开头的联系人,也就是我们常见的#。另外我们需要一个titileArray数组用来作为数组右侧的索引和每个section的标题。
    再次明确一下我们的目标:一个dataArray,包含27个subArray,另外需要一个titleArray。

    获取首字母

    如果我们的联系人都是英文名,这一步就很简单,但是有中文名怎么办呢? 没关系,OC其实给我们提供了一个方法用来将汉字转化成拼音,这样我们就能很方便的取到首字母了。
    我们首先写下获取首字母的方法

    - (NSString *)returnFirstWordWithString:(NSString *)str
    {
    NSMutableString * mutStr = [NSMutableString stringWithString:str];
    
     //将mutStr中的汉字转化为带音标的拼音(如果是汉字就转换,如果不是则保持原样)
    CFStringTransform((__bridge CFMutableStringRef)mutStr, NULL, kCFStringTransformMandarinLatin, NO);
    //将带有音标的拼音转换成不带音标的拼音(这一步是从上一步的基础上来的,所以这两句话一句也不能少)
    CFStringTransform((__bridge CFMutableStringRef)mutStr, NULL, kCFStringTransformStripCombiningMarks, NO);
    if (mutStr.length >0) {
         //全部转换为大写    取出首字母并返回
         NSString * res = [[mutStr uppercaseString] substringToIndex:1];
        return res;
    }
    else
        return @"";
    
    }
    
    按首字母分组排序

    前面说过,我们的27分别代表从A到Z再加上#,那么我们这一步就是要将上一步获得的首字母所对应的联系人放到相应的数组中去(比如把 奔跑的炸鸡放到第二个数组,因为它代表B开头的联系人)。
    那我们需要写27个if语句吗?
    当然不是,我们有更简单的方法,但是我们需要先回忆两个小知识点

    1. 记得A到Z对应的ASCⅡ码吗?是65到90。在Unicode编码中,A到Z对应的也是65到90。
    1. 记得在C语言中,一个char类型其实就是一个字节的int类型吗?如果将char作为int去取值,那么A就是65,Z就是90。

    通过以上两点我们就可以将拿到首字母的联系人直接放到对应的数组,无需任何比较

    接下来是代码

    - (void)dealDataWithArray:(NSArray *)array
    {
    
    NSMutableArray * tmpArray = [[NSMutableArray alloc]init];
    for (NSInteger i =0; i <27; i++) {
        //给临时数组创建27个数组作为元素,用来存放A-Z和#开头的联系人
        NSMutableArray * array = [[NSMutableArray alloc]init];
        [tmpArray addObject:array];
    }
    
    for (AddressModel * model in array) {
         //AddressMode是联系人的数据模型
        //转化为首拼音并取首字母
        NSString * nickName = [FunctionModule returnFirstWordWithString:model.nickname];
        int firstWord = [nickName characterAtIndex:0];
        
        //把字典放到对应的数组中去
        
        if (firstWord >= 65 && firstWord <= 90) {
       //如果首字母是A-Z,直接放到对应数组
                NSMutableArray * array = tmpArray[firstWord - 65];
                [array addObject:model];
            
        }
        else
        { 
            //如果不是,就放到最后一个代表#的数组
            NSMutableArray * array =[tmpArray lastObject];
            [array addObject:model];
        }
    }
    
    //此时数据已按首字母排序并分组
    //遍历数组,删掉空数组
    for (NSMutableArray * mutArr in tmpArray) {
        //如果数组不为空就添加到数据源当中
        if (mutArr.count != 0) {
            [self.dataArray addObject:mutArr];
            AddressModel * model = mutArr[0];
            NSString * nickName = [FunctionModule returnFirstWordWithString:model.nickname];
            int firstWord = [nickName characterAtIndex:0];
            //取出其中的首字母放入到标题数组,暂时不考虑非A-Z的情况
            if (firstWord >= 65 && firstWord <= 90) {
                [self.titleArray addObject:nickName];
            }
        }
    }
    //便利结束后,两个数组数目不相等说明有除大写字母外的其他首字母
    if (!(self.titleArray.count == self.dataArray.count)) {
        [self.titleArray addObject:@"#"];
    }
    
    //刷新tableView
    [self.tableView reloadData];
    }
    
    效果展示
    效果展示
    一些不算坑的坑

    1.右侧的索引列表,网上给出的答案是实现 - (NSArray *)titleArrayAtIndexes:(NSIndexSet *)indexes方法,但是实际上这个方法已经无效了,现在应该去实现
    - (NSArray<NSString *> *)sectionIndexTitlesForTableView:(UITableView *)tableView
    {
    return self.titleArray;
    }

    2.还是索引,默认的索引是文字是蓝色的,还会打一个白色的半透明图层,这两个东西其实是可以直接设置的。代码如下:

        //设置索引文字颜色
        self.tableView.sectionIndexColor = ColorFromRGB(0x646464);
        //设置索引背景颜色
        self.tableView.sectionIndexBackgroundColor = [UIColor clearColor];
    

    3.section的那种悬浮效果,只有当tableView的风格是Plain的时候才会有。

    4.tableView底部多余空白Cell可以通过设置TableViewFooter解决

    self.tableView.tableFooterView = [UIView new];
    

    结语

    最近事情有点多,拖了很久才写。
    这里只是提供个人使用的方法,如果有错误之处欢迎指出。
    如果我的文章对您有帮助,请点赞或评论。
    我们下篇文章见!

    相关文章

      网友评论

      • e939502bbb11: NSString * nickName = [FunctionModule returnFirstWordWithString:model.nickname];
        的FunctionModule 是什麼?
        您在前面沒有寫出來實在不理解,希望大神可以再詳細一點
        85aa2b26df43: @_奔跑的炸鸡 请问FunctionModule是什么类
        e939502bbb11:嘗試了幾天依然無法成功,可否提供Demo
        _奔跑的炸鸡:@L2EB 啊,这个是我自己得一个工具类.. 用来返回首字母的,实现我已经贴在文章里了
      • 十一岁的加重:随便找个环信,融云,网易云信,腾讯云之类的,都有这个
      • 左手一只鸭: NSString * nickName = [FunctionModule returnFirstWordWithString:model.nickname];

        这个是用类方法 调用对象方法吗? 在你的工程下是怎么运行的.... :cry:
        _奔跑的炸鸡:@左手一只鸭 这个方法我已经写在前面了啊,就是返回首字母的
      • 黑白之间:分组名悬浮这种效果只在手机端见过,想请教下 在网页端能实现么?非常感谢!
      • blingman123:能分享一下demo吗
      • 2f3e8481036f:拼音相同但是字不同的时候怎么处理? eg.姓于和姓俞的穿插排序。
        2f3e8481036f:@_奔跑的炸鸡 谢谢。
        _奔跑的炸鸡:@待绝笔墨痕干 愿意的话你可以对首字母相同的姓名,取第二个再次比较,但是实际需求中个人感觉意义不大
      • neobuger:支持 mark 一下
      • maretell:有没有demo? 可以看看嘛?
        _奔跑的炸鸡:@maretell 就是一个普通的TableView.. 没啥特别的..
      • SAW_:八错,这种排序筛选思路给力,省去了借用第三方pingying转换的类
        _奔跑的炸鸡:@SAW 谢谢夸奖:relieved::relieved::relieved:
      • 船长_:孔令涛
        SpringAnimation:我认识这个人,在嘉环科技
        船长_:@_奔跑的炸鸡 没
        _奔跑的炸鸡:@船长_ 我是不是暴漏了啥..

      本文标题:实现通讯录分组排序的一个方法

      本文链接:https://www.haomeiwen.com/subject/bwtslttx.html