美文网首页IoniciOS学习笔记
仿微信选择联系人列表

仿微信选择联系人列表

作者: 这个汤圆没有馅 | 来源:发表于2017-12-28 20:35 被阅读252次

    之前项目里有做选择联系人列表,于是仿照微信把功能模块抽出来写了个demo。

    索引的处理

    索引.gif
    • 联系人列表根据首字母排序并获取索引列表
    /**
     联系人数组排序
     
     @param array 原始联系人数组数据
     @return 排序后的联系人数组
     */
    + (NSMutableArray *) getContactListDataBy:(NSMutableArray *)array{
        
        NSMutableArray *ans = [[NSMutableArray alloc] init];
        
        NSArray *serializeArray = [(NSArray *)array sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {//排序
            int i;
            NSString *strA = [((ConatctModel *)obj1).name transformCharacter];// transformCharacter:获取姓氏首字母
            NSString *strB = [((ConatctModel *)obj2).name transformCharacter];
            for (i = 0; i < strA.length && i < strB.length; i ++) {
                char a = [strA characterAtIndex:i];
                char b = [strB characterAtIndex:i];
                if (a > b) {
                    return (NSComparisonResult)NSOrderedDescending;//上升
                }
                else if (a < b) {
                    return (NSComparisonResult)NSOrderedAscending;//下降
                }
            }
            
            if (strA.length > strB.length) {
                return (NSComparisonResult)NSOrderedDescending;
            }else if (strA.length < strB.length){
                return (NSComparisonResult)NSOrderedAscending;
            }else{
                return (NSComparisonResult)NSOrderedSame;
            }
        }];
        
        char lastC = '1';
        NSMutableArray *data;
        NSMutableArray *oth = [[NSMutableArray alloc] init];
        for (ConatctModel *contact in serializeArray) {
            char c = [[contact.name transformCharacter] characterAtIndex:0];
            if (!isalpha(c)) {
                [oth addObject:contact];
            }
            else if (c != lastC){
                lastC = c;
                if (data && data.count > 0) {
                    [ans addObject:data];
                }
                
                data = [[NSMutableArray alloc] init];
                [data addObject:contact];
            }
            else {
                [data addObject:contact];
            }
        }
        if (data && data.count > 0) {
            [ans addObject:data];
        }
        if (oth.count > 0) {
            [ans addObject:oth];
        }
        return ans;
    }
    
    
    /**
     获取分区数(姓氏首字母)
    
     @param array 排序后的联系人数组
     @return [A,B,C,D.....]
     */
    + (NSMutableArray *)getContactListSectionBy:(NSMutableArray *)array {
        
        NSMutableArray *section = [[NSMutableArray alloc] init];
        [section addObject:UITableViewIndexSearch]; // 索引栏最上方的搜索icon(可加可不加)
        for (NSArray *item in array) {
            ConatctModel *model = [item objectAtIndex:0];
            char c = [[model.name transformCharacter] characterAtIndex:0];
            if (!isalpha(c)) {
                c = '#';
            }
            [section addObject:[NSString stringWithFormat:@"%c", toupper(c)]];
        }
        return section;
    }
    
    • 点击索引列表时显示tipView,cell背景变为绿色,联系人列表滚动到对应的section。
    // indexTableView didSelectRow
        self.isScrollToShow = NO;// 这个属性后面会讲到
        self.selectIndex = indexPath.row;
        [_indexTableView reloadData];
        [_listTableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:indexPath.row-1] atScrollPosition:UITableViewScrollPositionTop animated:YES];
        [self showTipViewWithIndex:indexPath];
    
    /**
     显示tipView
     */
    - (void)showTipViewWithIndex:(NSIndexPath *)indexPath {
    
        CGFloat y = CGRectGetMinY(_indexTableView.frame) + indexPath.row*20;
        self.tipViewBtn.frame = CGRectMake(CGRectGetMinX(_indexTableView.frame)-70, y-12, 65, 50);
        [self.view addSubview:self.tipViewBtn];
        self.tipViewBtn.titleLabel.font = [UIFont systemFontOfSize:24];
        NSString *title = _sectionArr[self.selectIndex];
        [self.tipViewBtn setTitle:title forState:(UIControlStateNormal)];
        [self performSelector:@selector(dismissTipViewBtn) withObject:nil afterDelay:0.5];
    }
    - (void)dismissTipViewBtn {
        
        [self.tipViewBtn removeFromSuperview];
    }
    
    • 联系人列表滚动时, 索引列表要滚动到对应的字母
    - (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    
        if (self.isScrollToShow) { // 判断self.isScrollToShow,为NO时不显示tipView
            // 获取当前屏幕可见范围的indexPath
            NSArray *visiblePaths = [_listTableView indexPathsForVisibleRows];
            if (visiblePaths.count < 1) {
                return;
            }
            
            NSIndexPath *indexPath0 = visiblePaths[0];
    
            // 判断是否已滑到最底部
            CGFloat height = scrollView.frame.size.height;
            CGFloat contentOffsetY = scrollView.contentOffset.y;
            CGFloat bottomOffset = scrollView.contentSize.height - contentOffsetY;
            
            NSIndexPath *indexPath;
            if (bottomOffset <= height || fabs(bottomOffset - height) < 1) {
                //在最底部(显示最后一个索引字母)
                NSInteger row = _sectionArr.count-1;
                indexPath = [NSIndexPath indexPathForRow:row inSection:0];
                self.selectIndex = indexPath.row;
            }else {
                indexPath = [NSIndexPath indexPathForRow:indexPath0.section inSection:0];
                self.selectIndex = indexPath.row+1;
            }
            
            [_indexTableView reloadData];
        }
    }
    
    由于[_listTableView scrollToRowAtIndexPath: atScrollPosition: animated:];这个方法同时会触发- (void)scrollViewDidScroll:(UIScrollView *)scrollView,这个时候索引列表的UI会出现bug。因此设置属性self.isScrollToShow,默认值为YES,在点击索引时设为NO,不处理tipView显示,在滚动开始和结束时重置。
    - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
        // 重置
        if (!self.isScrollToShow) {
            self.isScrollToShow = YES;
        }
    }
    - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
        // 重置
        if (!self.isScrollToShow) {
            self.isScrollToShow = YES;
        }
    }
    

    头部View选择联系人UI处理

    头部view选择.gif
    • 头部封装一个包含collectionView和textField的view
    @protocol SelectMemberWithSearchViewDelegate <NSObject>
    // 点击collection cell取消选中
    - (void)removeMemberFromSelectArray:(ConatctModel *)member
                              indexPath:(NSIndexPath *)indexPath;
    @end
    
    @interface SelectMemberWithSearchView : UIView
    @property (nonatomic, weak) id<SelectMemberWithSearchViewDelegate> delegate;
    @property (nonatomic, strong) UICollectionView *collectionView;
    @property (nonatomic, strong) UITextField *textfield;
    
    // 当选中人数发生改变时 更改collection view UI
    - (void)updateSubviewsLayout:(NSMutableArray *)selelctArray;
    
    @end
    
    • 点击联系人列表cell,刷新选中状态并更新头部View的UI
    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
        
        [tableView deselectRowAtIndexPath:indexPath animated:YES];
        if (tableView == _listTableView) {
            ConatctModel *model = _rowArr[indexPath.section][indexPath.row];
            SelectContactCell *cell = [tableView cellForRowAtIndexPath:indexPath];
            cell.selectedBtn.selected = !cell.selectedBtn.selected;
            if (cell.selectedBtn.selected == YES) {
                [cell.selectedBtn setImage:[UIImage imageNamed:@"circle_green"] forState:(UIControlStateSelected)];
                [self.selectArray addObject:model];
            }else {
                [cell.selectedBtn setImage:[UIImage imageNamed:@"circle_empty"] forState:(UIControlStateNormal)];
                [self.selectArray removeObject:model];
            }
            [self updateRightBarButtonItem]; // 更改rightBarButtonItem
            [self.searchView updateSubviewsLayout:self.selectArray]; //刷新头部view的UI
        }
    }
    
    • 点击头部collectionView的cell,实现代理的方法,取消选中状态并更新UI
    - (void)removeMemberFromSelectArray:(ConatctModel *)member indexPath:(NSIndexPath *)indexPath {
        
        [_contactArray enumerateObjectsUsingBlock:^(ConatctModel * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
            
            if ([obj.name isEqualToString:member.name]) {
                [self.selectArray removeObject:obj];
                [_listTableView reloadData];
                [self updateRightBarButtonItem]; // 更改rightBarButtonItem
            }
        }];
    }
    

    关于搜索,这里偷个懒不想写了。思路都一样,判断cell的选中状态并更新列表,同时刷新头部View。后期有时间的话再更新

    👉🏾I'm the demo。

    相关文章

      网友评论

        本文标题:仿微信选择联系人列表

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