之前項(xiàng)目里有做選擇聯(lián)系人列表洁仗,于是仿照微信把功能模塊抽出來(lái)寫(xiě)了個(gè)demo茄猫。
索引的處理
索引.gif
-
聯(lián)系人列表根據(jù)首字母排序并獲取索引列表
/**
聯(lián)系人數(shù)組排序
@param array 原始聯(lián)系人數(shù)組數(shù)據(jù)
@return 排序后的聯(lián)系人數(shù)組
*/
+ (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;
}
/**
獲取分區(qū)數(shù)(姓氏首字母)
@param array 排序后的聯(lián)系人數(shù)組
@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;
}
-
點(diǎn)擊索引列表時(shí)顯示tipView瘩绒,cell背景變?yōu)榫G色,聯(lián)系人列表滾動(dòng)到對(duì)應(yīng)的section贬堵。
// indexTableView didSelectRow
self.isScrollToShow = NO;// 這個(gè)屬性后面會(huì)講到
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];
}
-
聯(lián)系人列表滾動(dòng)時(shí)恃轩, 索引列表要滾動(dòng)到對(duì)應(yīng)的字母
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
if (self.isScrollToShow) { // 判斷self.isScrollToShow,為NO時(shí)不顯示tipView
// 獲取當(dāng)前屏幕可見(jiàn)范圍的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) {
//在最底部(顯示最后一個(gè)索引字母)
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:];
這個(gè)方法同時(shí)會(huì)觸發(fā)- (void)scrollViewDidScroll:(UIScrollView *)scrollView
黎做,這個(gè)時(shí)候索引列表的UI會(huì)出現(xiàn)bug叉跛。因此設(shè)置屬性self.isScrollToShow
,默認(rèn)值為YES引几,在點(diǎn)擊索引時(shí)設(shè)為NO昧互,不處理tipView顯示,在滾動(dòng)開(kāi)始和結(jié)束時(shí)重置伟桅。
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
// 重置
if (!self.isScrollToShow) {
self.isScrollToShow = YES;
}
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
// 重置
if (!self.isScrollToShow) {
self.isScrollToShow = YES;
}
}
頭部View選擇聯(lián)系人UI處理
頭部view選擇.gif
-
頭部封裝一個(gè)包含collectionView和textField的view
@protocol SelectMemberWithSearchViewDelegate <NSObject>
// 點(diǎn)擊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;
// 當(dāng)選中人數(shù)發(fā)生改變時(shí) 更改collection view UI
- (void)updateSubviewsLayout:(NSMutableArray *)selelctArray;
@end
-
點(diǎn)擊聯(lián)系人列表cell敞掘,刷新選中狀態(tài)并更新頭部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
}
}
-
點(diǎn)擊頭部collectionView的cell,實(shí)現(xiàn)代理的方法楣铁,取消選中狀態(tài)并更新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
}
}];
}
關(guān)于搜索玖雁,這里偷個(gè)懶不想寫(xiě)了。思路都一樣盖腕,判斷cell的選中狀態(tài)并更新列表赫冬,同時(shí)刷新頭部View浓镜。后期有時(shí)間的話(huà)再更新