美文网首页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