美文网首页
CollectionView添加索引

CollectionView添加索引

作者: 铁头娃_e245 | 来源:发表于2018-09-21 14:50 被阅读0次

    在collectionView列表添加索引条, 因不像tableView的协议自带设置索引功能, 所以collectionView的索引需要自定义, 虽然麻烦点, 但也有更高的扩展性以应对更复(奇)杂(怪)的需求

    我们先来看一下完成效果: ①右侧索引条 ②点击/滑动索引条屏幕中心的提示框


    索引.gif

    需求分解: 先将需求分解成三步

    (1)绘制索引条
    (2)索引条与collectionView联动效果
    (3)制作提示框

    这里只介绍几个用到的技术点:

    (1)绘制索引条:

    使用CAShapeLayerUIBezierPath实现不在view的drawRect方法中就画出想要的图形, 下图是核心绘制代码

    UIBezierPath *bezierPath = [UIBezierPath bezierPath];
            [bezierPath moveToPoint:CGPointZero];
            [bezierPath addLineToPoint:CGPointMake(0, self.frame.size.height)];
            
            /*-----绘制文字部分------*/
            _letterHeight = 16;
            CGFloat fontSize = 12;
            [self.titleIndexes enumerateObjectsUsingBlock:^(NSString *obj, NSUInteger idx, BOOL *stop) {
                CGFloat originY = idx * _letterHeight;
                CATextLayer *ctl = [self textLayerWithSize:fontSize
                                                    string:obj
                                                  andFrame:CGRectMake(0, originY, self.frame.size.width, _letterHeight)];
    
                [self.layer addSublayer:ctl];
                
                [bezierPath moveToPoint:CGPointMake(0, originY)];
                [bezierPath addLineToPoint:CGPointMake(ctl.frame.size.width, originY)];
            }];
    
    //绘制字体
    - (CATextLayer*)textLayerWithSize:(CGFloat)size string:(NSString*)string andFrame:(CGRect)frame{
        CATextLayer *tl = [CATextLayer layer];
        [tl setFont:@"ArialMT"];
        [tl setFontSize:size];
        [tl setFrame:frame];
        [tl setAlignmentMode:kCAAlignmentCenter];
        [tl setContentsScale:[[UIScreen mainScreen] scale]];
        [tl setForegroundColor:RGB(168, 168, 168, 1).CGColor];
        [tl setString:string];
        return tl;
    }
    

    (2)索引条与collectionView联动效果:

    重写响应事件的方法

    #pragma mark- response事件
    //手指触碰屏幕,触摸开始
    -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
        [super touchesBegan:touches withEvent:event];
        [self sendEventToDelegate:event];
        [self.collectionDelegate collectionViewIndexTouchesBegan:self];
    }
    
    //手指在屏幕上移动
    - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
        [super touchesMoved:touches withEvent:event];
        [self sendEventToDelegate:event];
    }
    
    //手指离开屏幕,触摸结束
    - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
    {
        [self.collectionDelegate collectionViewIndexTouchesEnd:self];
    }
    
    //根据触摸事件的触摸点来算出点击的是第几个section
    - (void)sendEventToDelegate:(UIEvent*)event{
        UITouch *touch = [[event allTouches] anyObject]; //获取触摸对象
        CGPoint point = [touch locationInView:self];   //获取当前触摸点位置
        
        NSInteger indx = ((NSInteger) floorf(point.y) / _letterHeight);  //触摸位置对应的行数
        
        if (indx< 0 || indx > self.titleIndexes.count - 1) {
            return;
        }
        
        [self.collectionDelegate collectionViewIndex:self didselectionAtIndex:indx withTitle:self.titleIndexes[indx]];
        
    }
    

    (3)中文转成拼音以进行排序操作

    /**
     将中文字符串转换为拼音格式(不带声调)
     @return 返回不带声调拼音字符串
     */
    - (NSString *)transformToPinyin:(NSString *)str
    {
        // 空值判断
        if (str == nil || str == NULL) {
            return @"";
        }
        // 将字符串转为NSMutableString类型
        NSMutableString *string = [str mutableCopy];
        // 将字符串转换为拼音音调格式
        CFStringTransform((__bridge CFMutableStringRef)string, NULL, kCFStringTransformMandarinLatin, NO);
        // 去掉音调符号
        CFStringTransform((__bridge CFMutableStringRef)string, NULL, kCFStringTransformStripDiacritics, NO);
        // 返回不带声调拼音字符串
        return string;
    }
    

    (4)对数据进行删选(把接口提供的数据转化为我们需要的数据结构)

    接口提供数据:

    self.data = [NSMutableArray arrayWithArray:@[@"安卓", @"宝丽来",@"霸王别姬",@"菜鸟",@"facebook",@"菲尔可",@"飞利浦",@"谷歌",@"海尔",@"海信",@"华为",@"iPhone",@"iPad",@"Mac book",@"松下"]];
    

    因接口数据是按字母排序过得中文名称, 过滤代码如下, 时间复杂度是O(n)

    NSMutableArray *sections = [NSMutableArray array];    //创建字母数组   @[@"A", @"D", @"F", @"M", @"N", @"Z"];
        rows = [NSMutableArray array];  //创建索引数组   @[@[@"adam", @"alfred"],@[@"bo"]];
        int indexsInt = -1;    //更新索引数组元素的数值
        NSString *tempStr = @"temp";    //交换字母,用来判断该字母是否存在的数值
        for (NSString *nameStr in self.data) {
            NSString *pinyin = [self transformToPinyin:nameStr];    //将中文字符串转换为拼音格式
            if ([pinyin isEqualToString:@"zhang hong"]) {   //排错   长虹转换为拼音错误
                pinyin = @"chang hong";
            }
            NSString *testUpFirst = [pinyin capitalizedString];      //首字母大写
            NSString *firstLetterStirng = [testUpFirst substringToIndex:1];    //取出字符串第一位字母
            
            if (firstLetterStirng == tempStr) {   //判断该字母是否为上一位存在的
                [rows[indexsInt] addObject:firstLetterStirng];   //加入对应数组中
            }else{
                [sections addObject:firstLetterStirng];   //字母数组添加新字母
                NSMutableArray *array = [NSMutableArray array];   //生成新字母数组
                [array addObject:firstLetterStirng];
                [rows addObject:array];     //索引数组添加新字母数组
                indexsInt = indexsInt + 1;    //索引数组count+1
                tempStr = firstLetterStirng;    //上一位字母更换为新字母
            }
        }
    

    引申内容

    (5)数组遍历(enumerateObjectsUsingBlock)

    我们常用的循环方式:
    for循环 方便针对下标的处理, 适用面最广
    forin 效率更高, 但无法针对下标处理, 反向遍历不方便
    enumerateObjectsUsingBlock 底层通过GCD来处理并发执行事宜, 多线程来并发实现,并不保证按照顺序执行, 但效率最高

    [self.titleIndexes enumerateObjectsUsingBlock:^(NSString *obj, NSUInteger idx, BOOL *stop) {
          //obj代表内容, idx代表循环在第几个元素(row), stop用来停止循环
          CGFloat originY = idx *12;
    }];
    

    效率(遍历速度): enumerateObjectsUsingBlock > forin > for 尽量选择更高效的遍历方式

    (6)数组排序 (sortedArrayUsingComparator)

    // 数组的排序
        // 定义一个数组数组
        NSArray *array = @[@(3),@(5),@(4),@(2),@(1)];
        // 对数组进行排序(升序)
        NSArray *resultAscending = [array sortedArrayUsingComparator:^NSComparisonResult(id  _Nonnull obj1, id  _Nonnull obj2) {
            NSLog(@"%@ ~ %@", obj1, obj2);
            return [obj1 compare:obj2];
        }];
        NSLog(@"对数组进行排序(正序):%@", resultAscending);
        // 对数组进行排序(降序)
        NSArray *resultDescending = [array sortedArrayUsingComparator:^NSComparisonResult(id  _Nonnull obj1, id  _Nonnull obj2) {
            NSLog(@"%@ ~ %@", obj1, obj2);
            return [obj2 compare:obj1];
        }];
        NSLog(@"对数组进行排序(降序):%@", resultDescending);
        // 对数组进行排序(乱序)
        NSArray *resultBreak = [resultAscending sortedArrayUsingComparator:^NSComparisonResult(id  _Nonnull obj1, id  _Nonnull obj2) {
            NSLog(@"%@ ~ %@", obj1, obj2);
            if (arc4random_uniform(2) == 0) { // arc4random_uniform会随机返回一个0到上界之间(不含上界)的整数。以2为上界会得到0或1,像投硬币一样
                return [obj2 compare:obj1];// descending
            } else {
                return [obj1 compare:obj2];// ascending
            }
        }];
        NSLog(@"对数组进行排序(乱序):%@", resultBreak);
    

    参考文献:
    UICollectionView 加字母索引
    iOS触摸事件
    iOS数组遍历 (enumerateObjectsUsingBlock)
    iOS数组排序 (sortedArrayUsingComparator)

    Demo下载地址:
    GitHub下载

    相关文章

      网友评论

          本文标题:CollectionView添加索引

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