iOS tableView类似携程/美团城市筛选,自定义sectionIndex

很多app中都需要城市选择,最近自己写了一个城市筛选、搜索功能,以及tableView双表联动,上拉自动至下一个分类,tableView的折叠布局。

Demo 传送门

一、双表联动

1、上拉至下一个分类


  1.  

iOS tableView类似携程/美团城市筛选,自定义sectionIndex

  •  给rightTableView添加footRefresh 在刷新回调的时候进行操作,给leftTableView选中至当前的下一个indexPathRow 并同时将下一个rightTableView分类的dataSource传送过去,并刷新leftTableView、rightTableView两个表。将leftTableView当前选中的indexPath滚动到顶部。
#pragma mark - rightTableView刷新回调
- (void)childTableCallback {
    LBWeakSelf(self);
    self.childTableView.freshFinishCallback = ^ {
        LBStrongSelf(self);
        [self setCurrentIndexWithRow:self.currentIndex.row+1];
    };
}
- (void)setCurrentIndexWithRow:(NSInteger)row {
    NSIndexPath *currentIndex = [NSIndexPath indexPathForRow:row inSection:0];
    // 调用leftTableView的didSelectRowAtIndexPath方法实现选中下一个indexPathRow
    [self.baseTableView tableView:self.baseTableView.baseTableView didSelectRowAtIndexPath:currentIndex];
    // 记录当前选中的indexPath
    self.currentIndex = currentIndex;
    [self.baseTableView setValue:self.currentIndex forKey:@"selectedIndex"];
    [self.baseTableView.baseTableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:row inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:YES];
}
  • 点击leftTableView 将当前的分类数据传送给rightTableView并刷新rightTableView。
#pragma mark - leftTableView点击回调
- (void)baseTableViewCallback {
    LBWeakSelf(self);
    self.baseTableView.didSelectCellCallback = ^(NSIndexPath *indexPath, UITableViewCell *currentBaseCell) {
        LBStrongSelf(self);
        LBModel* model = self.dataSource[indexPath.row];
        // 数据源传给rightTableView
        [self.childTableView setValue:model.cityList forKey:@"childData"];
        // 刷新rightTableView
        [self.childTableView reload];
        self.currentIndex = indexPath;
    };
}

2、所有区联动

iOS tableView类似携程/美团城市筛选,自定义sectionIndex

  • 监听rightTableView滚动,并获取当前屏幕第一个section回调给leftTableView进行刷表同时将当前的section滚动到顶部 
- (void)scrollwithIndex:(NSIndexPath *)index {
    self.selectedIndex = index;
    //tableview滚动到指定的行:
    [self.baseTableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:index.row inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:YES];
    [self.baseTableView reloadData];
}

二、tableView折叠

iOS tableView类似携程/美团城市筛选,自定义sectionIndex

  • 定义BOOL值isFlod 记录是否可以展开,定义currentIndex记录当前展开的index 
// 是否可以展开
@property(nonatomic, assign)BOOL isFlod;
// 当前展开的index
@property(nonatomic, assign)NSInteger currentIndex;
```
- 给tableViewSection添加UIButton并设置tag为当前section
 
```
    sectionBtn.tag = section;
    sectionBtn.selected = self.currentIndex==section&&self.isFlod==YES?YES:NO;
  • Button点击方法设置isFlod值和currentIndex值并刷新tableView
- (void)sectionSelect:(UIButton*)sender {
    self.currentIndex = sender.tag;
    sender.selected = !sender.selected;
    self.isFlod = sender.selected;
    [self.foldTableView reloadData];
}
  • 在tableView数据源方法中,判断当前的section是否为展开状态并给出当前section有多少row
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    if (self.currentIndex == section) {
        LBModel* childModel = self.dataSource[section];
        return self.isFlod==YES?childModel.cityList.count:0;
    }
    return 0;
}

三、城市筛选

iOS tableView类似携程/美团城市筛选,自定义sectionIndex

  • 前面2个section分别是历史的筛选和热门筛选tableViewCell嵌套的collectionView,后面是按照首字母A~Z的分区城市的tableViewCell,这个不多说了,由于我的地址数据是按照省市区分的,所以自己又重新排了一次数据结构。 

汉字转拼音

//获取拼音首字母(传入汉字字符串, 返回大写拼音首字母)
+(NSString *)FirstCharactor:(NSString *)pString {
    //转成了可变字符串
    NSMutableString *pStr = [NSMutableString stringWithString:pString];
    //先转换为带声调的拼音
    CFStringTransform((CFMutableStringRef)pStr,NULL, kCFStringTransformMandarinLatin,NO);
    //再转换为不带声调的拼音
    CFStringTransform((CFMutableStringRef)pStr,NULL, kCFStringTransformStripDiacritics,NO);
    //多音字处理
    if ([[(NSString *)pString substringToIndex:1] compare:@"长"] == NSOrderedSame) {
        [pStr replaceCharactersInRange:NSMakeRange(0, 5) withString:@"chang"];
    }
    if ([[(NSString *)pString substringToIndex:1] compare:@"沈"] == NSOrderedSame) {
        [pStr replaceCharactersInRange:NSMakeRange(0, 4) withString:@"shen"];
    }
    if ([[(NSString *)pString substringToIndex:1] compare:@"厦"] == NSOrderedSame) {
        [pStr replaceCharactersInRange:NSMakeRange(0, 3) withString:@"xia"];
    }
    if ([[(NSString *)pString substringToIndex:1] compare:@"地"] == NSOrderedSame) {
        [pStr replaceCharactersInRange:NSMakeRange(0, 3) withString:@"di"];
    }
    if ([[(NSString *)pString substringToIndex:1] compare:@"重"] == NSOrderedSame) {
        [pStr replaceCharactersInRange:NSMakeRange(0, 5) withString:@"chong"];
    }
    //转化为大写拼音    
    NSString *pPinYin = [pStr uppercaseString];  // lowercaseString 转小写
    /*如果要返回所有的汉字转拼音,直接return pPinYin就可以了,转完的是中间带有空格的拼音,下面是去掉中间空格的方法*/
    /**去空格
    NSString *ciytString = [NSString stringWithFormat:@"%@", pPinYin];
    NSString *cityName = [ciytString stringByReplacingOccurrencesOfString:@" "     withString:@""]; */
    //获取并返回首字母
    return [pPinYin substringToIndex:1];
}

判断字符串中是否包含有汉字

// 是否包含汉字
- (BOOL)includeChinese {
    for(int i=0; i< [self length];i++) {
        int a =[self characterAtIndex:i];
        if( a >0x4e00&& a <0x9fff){
            return YES;
        }
    }
    return NO;
}
  • 最上面2个section的cell点击回调
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
    LBCollectionCell * cell = (LBCollectionCell *)[collectionView cellForItemAtIndexPath:indexPath];
    LBCollectionCell * currentCell;
    if (self.index.section==0&&indexPath.row!=0) {
        currentCell = (LBCollectionCell *)[collectionView cellForItemAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]];
    }
    if (self.index.section==1&&indexPath.row!=[self.selectedHotIndex integerValue]) {
        currentCell = (LBCollectionCell *)[collectionView cellForItemAtIndexPath:[NSIndexPath indexPathForRow:[self.selectedHotIndex integerValue] inSection:0]];
    }
    cell.title.backgroundColor = LBUIColorWithRGB(0x3CB371, .5);
    cell.title.textColor = LBUIColorWithRGB(0x228B22, 1);
    currentCell.title.backgroundColor = LBUIColorWithRGB(0xF5F5F5, 1);
    currentCell.title.textColor = LBUIColorWithRGB(0x130202, 1);
    
    if (self.collectionCallback) {
        self.collectionCallback(self.dataArray[indexPath.item],indexPath.item,self.index);
    }
}
#pragma mark - 历史和热门cell点击的回调--historyAndHotCellCallback
- (void)historyAndHotCellCallback:(LBHistoryCell *)cell {
    LBWeakSelf(self);
    cell.collectionCallback = ^(NSString *selectText,NSInteger collectionSelectIndex,NSIndexPath *index) {
        LBStrongSelf(self);
        if (index.section==1) { // 热门回调,存入缓存
            [LBUserDefaultTool saveHotSelectedData:collectionSelectIndex];
        } else {                // 历史回调
            NSMutableDictionary* dict = self.dataSource[1];
            NSMutableArray* cellArr = dict[@"cityName"];
            // 清热门选中缓存,重新存
            [LBUserDefaultTool removeHotSelected];
            // 查找热门中的数据与历史里选中的数据相同
            [cellArr enumerateObjectsUsingBlock:^(id object, NSUInteger idx, BOOL *stop) {
                if ([object isEqualToString:selectText]) {
                    [LBUserDefaultTool saveHotSelectedData:idx];
                }
            }];
        }
        if (self.selectCallback) {
            self.selectCallback(selectText);
        }
    };
}
  • 下面tableViewCell点击回调
#pragma mark - tableViewDelegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    [tableView deselectRowAtIndexPath:indexPath animated:NO];
    // 下面tableView点击
    if (indexPath.section!=0&&indexPath.section!=1) {
        [LBUserDefaultTool removeHotSelected];
        NSMutableDictionary* dict = self.dataSource[indexPath.section];
        NSString* selectText = dict[@"cityName"][indexPath.row];
        if (self.selectCallback) {
            self.selectCallback(selectText);
        }
    }
    // cell选中的标记符变化和titleLabel颜色变化
    LBCityCell *cell = [tableView cellForRowAtIndexPath:indexPath];
    LBCityCell *currentCell = [tableView cellForRowAtIndexPath:self.currentSelectedIndex];
    currentCell.cityLabel.textColor = LBUIColorWithRGB(0x130202, 1);
    currentCell.selectedImg.alpha = 0;
    cell.selectedImg.alpha = 1;
    cell.cityLabel.textColor = LBUIColorWithRGB(0x228B22, 1);
}

四、城市搜索

iOS tableView类似携程/美团城市筛选,自定义sectionIndex

  •  UITextField实时监听input输入,input的length大于1,去遍历所有数据查找,利用上面汉字转拼音并去空格的方法,与input的数据作对比,如果城市的拼音数据包含了input的数据,拼接成model并存入searchArray数组中作为searchTableView的dataSource展示。 
// 搜索input实时搜索
- (void)setSearchWithInputText:(NSString *)inputText {
    if (inputText.length > 0) {     // 这里判断length要大于0,是因为汉字转拼音的方法不能传空值
        [self.searchArray removeAllObjects];
        // length大于1,进行数据对比
        if ([NSString transform:inputText].length > 1) {
            // 循环所有数据
            [self.dataSource enumerateObjectsUsingBlock:^(id object, NSUInteger idx, BOOL *stop) {
                NSDictionary* dict = object;
                // firstText A~Z字母
                NSString* firstText = dict[@"cityId"];
                // 输入的(汉字转拼音)首字母是否属于A~Z之间 并拼接数据存入搜索数组searchArray中
                if ([[NSString FirstCharactor:inputText] isEqualToString:firstText]) {
                    NSMutableDictionary* tempDict = @{}.mutableCopy;
                    NSMutableArray* tempArr = @[].mutableCopy;
                    tempDict[@"cityId"] = firstText;
                    // 遍历所有城市的数组
                    [dict[@"cityName"] enumerateObjectsUsingBlock:^(id object, NSUInteger idx, BOOL *stop) {
                        NSString* cityName = object;
                        // 所有城市的拼音包含输入的拼音,就是符合的数据,存入搜索的数组中
                        if ([[NSString transform:cityName] containsString:[NSString transform:inputText]]) {
                            [tempArr addObject:cityName];
                        }
                    }];
                    tempDict[@"cityName"] = tempArr;
                    [self.searchArray addObject:tempDict];
                }
            }];
        }
        self.searchTableView.alpha = [NSString transform:inputText].length>1?1:0;
        [self.searchTableView setValue:self.searchArray forKey:@"dataSource"];
    } else {
        self.searchTableView.alpha = 0;
    }
}

五、自定义indexView

iOS tableView类似携程/美团城市筛选,自定义sectionIndex

iOS tableView类似携程/美团城市筛选,自定义sectionIndex 

  • 定义indexView,实现dataSource和delegate方法 
@protocol LBIndexViewDataSource <NSObject>
// 返回一共多少个section
- (NSInteger)numberOfItemViewForSectionIndexView:(LBIndexView *)sectionIndexView;
// 返回每个section的title
- (NSString *)sectionIndexView:(LBIndexView *)sectionIndexView
               titleForSection:(NSInteger)section;
@end

@protocol LBIndexViewDelegate <NSObject>
// 点击IndexItemView事件
- (void)sectionIndexView:(LBIndexView *)sectionIndexView
        didSelectSection:(NSInteger)section;
@end
#pragma mark - LBIndexViewDataSource
- (NSInteger)numberOfItemViewForSectionIndexView:(LBIndexView *)sectionIndexView {
    return self.cityTableView.numberOfSections;
}

- (NSString *)sectionIndexView:(LBIndexView *)sectionIndexView titleForSection:(NSInteger)section {
    NSMutableArray* sectionArr = @[].mutableCopy;
    [self.dataSource enumerateObjectsUsingBlock:^(id object, NSUInteger idx, BOOL *stop) {
        NSMutableDictionary* dict = object;
        [sectionArr addObject:dict[@"cityId"]];
    }];
    
    return sectionArr[section];
}
#pragma mark - LBIndexViewDelegate
- (void)sectionIndexView:(LBIndexView *)sectionIndexView didSelectSection:(NSInteger)section {
    [self.cityTableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:section] atScrollPosition:UITableViewScrollPositionTop animated:YES];
}
  • 下面是indexView的几个属性配置
// 是否显示选中提示图,默认是YES
@property(nonatomic, assign)BOOL isShowCallout;
// 选中提示图的样式
@property(nonatomic, assign)NSInteger calloutViewType;
// 选中背景的样式
@property(nonatomic, assign)NSInteger titleBGViewType;
// 提示图的主题色
@property(nonatomic, strong)UIColor* schemeColor;
  • 实现reloadIndeView方法
// 创建数据源
- (void)reloadIndexView {
    NSInteger numberOfItems = 0;
    if (_dataSource && [_dataSource respondsToSelector:@selector(numberOfItemViewForSectionIndexView:)]) {
        numberOfItems = [_dataSource numberOfItemViewForSectionIndexView:self];
    }
    for (int i = 0; i < numberOfItems; i++) {
        if (_dataSource && [_dataSource respondsToSelector:@selector(sectionIndexView:titleForSection:)]) {
            LBIndexItemView* itemView = [LBIndexItemView new];
            itemView.section = i;
            itemView.titleLabel.text = [_dataSource sectionIndexView:self titleForSection:i];
            itemView.schemeColor = self.schemeColor?self.schemeColor:LBUIColorWithRGB(0x228B22, 1);
            [self.itemViewList addObject:itemView];
            [self addSubview:itemView];
        }
    }
    [self layoutItemViews];
}
// 布局
- (void)layoutItemViews {
    if (self.itemViewList.count) {
        self.itemViewHeight = LBScreenH/3*2/(CGFloat)(self.itemViewList.count);
    }
    __block CGFloat offsetY = 0.f;
    [self.itemViewList enumerateObjectsUsingBlock:^(id object, NSUInteger idx, BOOL *stop) {
        LBIndexItemView *itemView = object;
        [itemView setHighlighted:NO animated:NO section:idx type:self.titleBGViewType];
        [itemView mas_makeConstraints:^(MASConstraintMaker *make) {
            make.centerX.offset(0);
            make.top.offset(offsetY);
            make.width.mas_equalTo(idx==0||idx==1?LBFit(30):self.itemViewHeight);
            make.height.mas_equalTo(self.itemViewHeight);
        }];
        offsetY += self.itemViewHeight;
    }];
}

分别实现4个touch方法,也是indexView的核心

  • touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    self.bgView.hidden = NO;
    UITouch *touch = [touches anyObject];
    // 获取到touch的point
    CGPoint touchPoint = [touch locationInView:self];
    // 遍历indexView的数据源,做点击操作和highlight操作
    for (LBIndexItemView *itemView in self.itemViewList) {
        if (CGRectContainsPoint(itemView.frame, touchPoint)) {
            [self selectItemViewForSection:itemView.section];
            self.highlightedItemIndex = itemView.section;
            return;
        }
    }
    self.highlightedItemIndex = -1;
}
  • touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    self.bgView.hidden = NO;
    UITouch *touch = [touches anyObject];
    CGPoint touchPoint = [touch locationInView:self];
    
    for (LBIndexItemView *itemView in self.itemViewList) {
        if (CGRectContainsPoint(itemView.frame, touchPoint)) {
            if (itemView.section != self.highlightedItemIndex) {
                [self selectItemViewForSection:itemView.section];
                self.highlightedItemIndex = itemView.section;
                return;
            }
        }
    }
}
  • touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
    self.bgView.hidden = YES;
    // 取消所有higlight的item
    [self unhighlightAllItems];
    self.highlightedItemIndex = -1;
}
  • touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    [self touchesCancelled:touches withEvent:event];
}

以上是自己写的关于tableView的一些Demo,欢迎小伙伴们指导,共同学习,共同进步

上一篇:课程管理模块开发_02


下一篇:fabric配置文件讲解整理(一) core.yaml