最近在做一个小功能时遇到了以下的问题:在调用了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了!