项目中常用到列表赛选,一般来说都是一列、两列的,这段时间我自己项目用到了三列,网上也没见到很好的Demo参考,无奈自己按着自己的想法写了一个,存粹提供一种方法供大家参考下。
这个Demo我仅仅写了一个三列的表格,没有做表头item的封装。至于一列、两列就更简单了,几乎毫无难度,大家自行撸过去即可。
先上效果图:
使用:我想足够简单了.......
- (void)viewDidLoad {
[super viewDidLoad];
self.dropView = [[YLDropDownTableView alloc] initWithFrame:CGRectMake(0, 40 + 64, self.view.frame.size.width, 350)];
self.dropView.delegate = self;
[self.view addSubview:self.dropView];
//构造数据
for (int i = 0; i < 6; i++) {
//一维数组
[self.dropView.firstData addObject:[NSString stringWithFormat:@"第一列 %d",i]];
NSMutableArray *two0 = [NSMutableArray array];
NSMutableArray *third0 = [NSMutableArray array];
for (int j = 0; j < 7; j++) {
[two0 addObject:[NSString stringWithFormat:@"第二列 %d-%d",i,j]];
NSMutableArray *third1 = [NSMutableArray array];
for (int k = 0; k < 15; k++) {
[third1 addObject:[NSString stringWithFormat:@"第三列 %d-%d-%d",i,j,k]];
}
[third0 addObject:third1];
}
//二维数组
[self.dropView.secondeData addObject:two0];
//三维数组
[self.dropView.thirdData addObject:third0];
}
[self.dropView reloadData];
}
//show
- (IBAction)showDropView:(id)sender {
[self.dropView show];
}
#pragma mark -- YLDropDownTableViewDelegate
- (void)didSeleted_ylDropDownWithFirstStr:(NSString *)firstTitle andSecondTitle:(NSString *)secondTitle andThirdTitle:(NSString *)thirdTitle {
NSLog(@"1 : %@ 2 : %@ 3 : %@", firstTitle, secondTitle, thirdTitle);
}
//点击下部蒙版
- (void)touchShadowView {
NSLog(@"点击了蒙版");
}
代码不多,就是三列构造数据第三列需要三维数组,大家注意下就行了。下面简单说下核心代码的思路。
我认为这个只有一个难点,就是数据的记录,即上次点击后的如果改变这行的文字状态,甚至加上一个✅选择。
在数据记录上,我用了一个不高雅但是很方便的办法,用数组构造记录下标。
self.selectedArray = [NSMutableArray arrayWithArray:@[@"0", @"0",@"0"]];
self.IndexPathArray = [NSMutableArray arrayWithArray:@[@"0",@"0"]];
上面两行代码,如果我不解释你可能无比懵逼。第一个数组是我用来记录最终选择的下标值(也就是点击了第三列),一共三列三个元素。
第二个数组是我用来记录每次点选第一列和第二列时候的下标的,用于刷新第二列和第三列的数据。这个只有两个元素,仅仅记录第一列点击和第二列点击即可,因为点了第二列第三列会刷新,这时候没有点击第三列,self.selectedArray这个数组就不会被赋值,所以不需要三个元素。
当需要的第三个时候也就意味着点击了第三列做了最终选择,这时候直接对self.selectedArray赋值即可。如下:
#pragma mark - UITableViewDelegate,
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if (tableView == self.leftTableView) {
self.IndexPathArray[0] = [NSString stringWithFormat:@"%ld", indexPath.row];
//很重要的一步,把第二列的记录初始化,避免此时第二列已经点击被记录其他值
//如果这个值大于下一次刷新的第二列的数组个数,会发生数组越界的崩溃
//点击第一列,相当于后面两列数据从新分配,所以这里修改为初始值
self.IndexPathArray[1] = @"0";
[self.midTableView reloadData];
[self.rightTableView reloadData];
}else if (tableView == self.midTableView) {
self.IndexPathArray[1] = [NSString stringWithFormat:@"%ld", indexPath.row];
[self.rightTableView reloadData];
}else {
NSInteger selected2 = [self.IndexPathArray[1] integerValue];
UIImageView *imgV = [cell.contentView viewWithTag:101];
if (selected2 == indexPath.row && [self.selectedArray[0] isEqual: self.IndexPathArray[0]] && [self.selectedArray[1] isEqual:self.IndexPathArray[1]]) {
imgV.hidden = NO;
}
//进行赋值。记录最终所选项的对应index
self.selectedArray[0] = self.IndexPathArray[0];
self.selectedArray[1] = self.IndexPathArray[1];
self.selectedArray[2] = [NSString stringWithFormat:@"%ld",indexPath.row];
//刷新3列
[self.leftTableView reloadData];
[self.midTableView reloadData];
[self.rightTableView reloadData];
if (self.delegate && [self.delegate respondsToSelector:@selector(didSeleted_ylDropDownWithFirstStr:andSecondTitle:andThirdTitle:)]) {
UILabel *label = [cell.contentView viewWithTag:100];
[self.delegate didSeleted_ylDropDownWithFirstStr:self.firstData[[self.selectedArray[0] integerValue]] andSecondTitle:self.secondeData[[self.selectedArray[0] integerValue]][[self.selectedArray[1] integerValue]] andThirdTitle:label.text];
}
//延迟0.1为了等待UI刷新动画
[self performSelector:@selector(dismiss) withObject:self afterDelay:0.1];
}
}
上面是我对三个列表点击时做的不同的处理。
其中有一处尤为重要,我已经写了备注。就是在点击第一列的时候。
这行代码
self.IndexPathArray[1] = @"0";
当点击第一列的时候就意味着第二、三列的数据肯定会刷新,这时候如果你已经做了第二列选择。例如你选择了第二列第三个元素,再去点击第一列,一旦这时候第一列只有两个数据,必然发生数组越界崩溃。为什么这样呢?看下面代码
#pragma mark - UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (tableView == self.leftTableView) {
return self.firstData.count ? self.firstData.count : 0;
}else if (tableView == self.midTableView) {
NSInteger index = [self.IndexPathArray[0] integerValue];
NSArray *array = self.secondeData[index];
return array.count ? array.count : 0;
}else {
NSInteger index = [self.IndexPathArray[0] integerValue];
NSInteger index1 = [self.IndexPathArray[1] integerValue];
NSArray *array = self.thirdData[index][index1];
return array.count ? array.count : 0;
}
我们看到。第三列的数据是根据这行代码
NSInteger index1 = [self.IndexPathArray[1] integerValue];
从这里拿到下标,在前面你点选了第二列。那这个被改成了3.这时候找数据一共只有两个,你去找第三个,就崩了。因此当点选第一个列表的时候,我们有必要把这个数据设为最初始的值也就是0;这样拉取第二列和第三列数据的时候才不会有问题。
下面cell创建我也贴出来吧,为了方便,我直接在数据源方法里创建并且设置了cell样式
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:@"cell"];
YLInsetLabel *titleLabel = [[YLInsetLabel alloc] initWithFrame:CGRectMake(0, 0, 100, 44)];
//设置label的�内边距
titleLabel.insets = UIEdgeInsetsMake(0, 20, 0, 0);
titleLabel.tag = 100;
titleLabel.textColor = [UIColor blackColor];
titleLabel.font = [UIFont systemFontOfSize:13];
[cell.contentView addSubview:titleLabel];
if (tableView == self.rightTableView) {
UIImageView *imgV = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"list_selected"]];
imgV.frame = CGRectMake(10, (44-15) / 2, 15, 15);
imgV.hidden = YES;
imgV.tag = 101;
[cell.contentView addSubview:imgV];
titleLabel.frame = CGRectMake(20, 0, self.frame.size.width - 200 - 20 - 20, 44);
}else {
cell.selectedBackgroundView = [[UIView alloc] initWithFrame:cell.frame];
cell.selectedBackgroundView.backgroundColor = [UIColor groupTableViewBackgroundColor];
}
}
UILabel *label = [cell.contentView viewWithTag:100];
if (tableView == self.leftTableView) {
cell.backgroundColor = [UIColor whiteColor];
label.text = self.firstData[indexPath.row];
//满足一个条件,即可认为是上次选择项
if ([self.selectedArray[0] integerValue] == indexPath.row) {
label.textColor = SelectedColor;
}else {
label.textColor = [UIColor blackColor];
}
}else if (tableView == self.midTableView) {
cell.backgroundColor = [UIColor colorWithRed:250/255. green:250/255. blue:250/255. alpha:1];
NSInteger selected = [self.IndexPathArray[0] integerValue];
label.text = self.secondeData[selected][indexPath.row];
//同时满足两个tiao'j.即认为是上次选择的cell
if([self.selectedArray[0] isEqual:self.IndexPathArray[0]] && [self.selectedArray[1] integerValue] == indexPath.row) {
label.textColor = SelectedColor;
}else {
label.textColor = [UIColor blackColor];
}
}else {
cell.backgroundColor = [UIColor groupTableViewBackgroundColor];
NSInteger selected1 = [self.IndexPathArray[0] integerValue];
NSInteger selected2 = [self.IndexPathArray[1] integerValue];
UIImageView *imgV = [cell.contentView viewWithTag:101];
//同时满足三个条件,即认为是上次选择的cell
if ([self.selectedArray[2] integerValue] == indexPath.row && [self.selectedArray[0] isEqual:self.IndexPathArray[0]] && [self.selectedArray[1] isEqual:self.IndexPathArray[1]]) {
imgV.hidden = NO;
label.textColor = SelectedColor;
}else {
imgV.hidden = YES;
label.textColor = [UIColor blackColor];
}
label.text = self.thirdData[selected1][selected2][indexPath.row];
}
return cell;
}
一大堆,确实不利于观看,你们可以把这个单独写进cell类中,让代码清爽一些。
其他我就不啰嗦了,如果有帮助给个喜欢。
GitHub Demo 喜欢请star : 传送门
iOS技术交流群:511860085 欢迎加入!