最近在做一个小功能时遇到了以下的问题:在调用了reloadData后,再将tableView的contentoffset设置回(0,0)时发现tableView的位置比预期的要偏下一点。
本着学习的精神,对这一诡异的现象进行了研究和分析。
首先问题的表现是这样的,键盘弹起时
键盘弹起时没什么问题,然后点击了自动汇总后的UISwitch或者键盘的Done后,界面就变成如下的形式了
好吧,只能看下代码到底出了什么问题了
#pragma mark - Table view data source - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 2; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return section != 1 ? 5 : (_sectionNum ? 1 : 2); } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { //static NSString *CellIdentifier = @"Cell"; //UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; // if (cell == nil) { // // } UITableViewCell * cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil]; cell.selectionStyle = UITableViewCellSelectionStyleNone; if (indexPath.section == 0) { cell.textLabel.text = [NSString stringWithFormat:@"Row --- %d ", indexPath.row]; cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; } else { if (indexPath.row == 0) { UILabel * label = [[UILabel alloc] initWithFrame:CGRectMake(10, 11, 100, 20)]; label.text = @"自动汇总"; UISwitch * mySwitch = [[UISwitch alloc] initWithFrame:CGRectMake(253, 7, 51, 31)]; mySwitch.on = _sectionNum; [mySwitch addTarget:self action:@selector(mySwitchValueChanged:) forControlEvents:UIControlEventValueChanged]; [cell.contentView addSubview:mySwitch]; [cell.contentView addSubview:label]; } else { UITextField * textField = [[UITextField alloc] initWithFrame:CGRectMake(104, 2, 200, 40)]; textField.placeholder = @"Intput your Budget"; textField.textAlignment = NSTextAlignmentRight; textField.keyboardType = UIKeyboardTypeNumbersAndPunctuation; textField.returnKeyType = UIReturnKeyDone; textField.delegate = self; textField.tag = 1000; [cell.contentView addSubview:textField]; } } return cell; }
- (void)mySwitchValueChanged:(UISwitch *)sender { _sectionNum = sender.on; if (!_sectionNum) { [self performSelector:@selector(textFieldBecomeFirstResponder) withObject:nil afterDelay:0.1]; } else { UITextField * textField = (UITextField *)[self.tableView viewWithTag:1000]; [textField resignFirstResponder]; } [self.tableView reloadData]; }
self.tableView reloadSections: withRowAnimation:的方法来进行适当的优化,不过在这里影响也不大,此外,如果使用上面的方法关闭时也存在类似的问题,所以根本原因不在这里。
上面采用延时的方法设置textField为第一响应者,是由于项目中的某些特殊的原因,在该页面不会有-(void)viewDidAppear:(BOOL)animated调用。
既然到这里都不是问题的根本原因,那么问题只可能出现在下面的方法中了
- (void)textFieldDidEndEditing:(UITextField *)textField { [self.tableView setContentOffset:CGPointZero animated:YES]; }
方法本身没什么问题,一般也都是这样用的,那么问题究竟出在哪儿呢。。。
经过分析发现问题确实是由这里引起的,如果将animated设置为NO,问题就解决了。
原来一般情况下调用reloadData时tableView的 contentoffset是不会变的,但是如果table里面cell的数目发生的改变,如增加了一个cell,并且无法从重用队列中找到时,talbeView会重排结构,contentoffset会清零。并且这一过程是需要时间的,如果在上述动作尚未完成之前又去设置与table相关的动画,会引起冲突,从而导致重排后的tableView的布局与预期出现偏差的情况。故,解决上述问题还可将设置tableView的contentoffset的动作延后或者放到UIView的动画回调中,因为原理上是一样的,都避开了tableView本身重排的时间。
如果你在IOS开发中碰到了比较诡异的界面布局问题,并且这一过程和动画有关,那么不妨把动画关了试试,说不定就OK了!
完整的代码