由UITableView reloadData后引起的界面布局问题分析

最近在做一个小功能时遇到了以下的问题:在调用了reloadData后,再将tableView的contentoffset设置回(0,0)时发现tableView的位置比预期的要偏下一点。

本着学习的精神,对这一诡异的现象进行了研究和分析。


首先问题的表现是这样的,键盘弹起时

由UITableView reloadData后引起的界面布局问题分析_第1张图片


键盘弹起时没什么问题,然后点击了自动汇总后的UISwitch或者键盘的Done后,界面就变成如下的形式了


由UITableView reloadData后引起的界面布局问题分析_第2张图片



 神马情况。。。。由UITableView reloadData后引起的界面布局问题分析_第3张图片


好吧,只能看下代码到底出了什么问题了

#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;
}


创建这里貌似没有什么,因为cell的样式不一样,所以放弃了重用,另外如果有人对不同样式的cell整合到一个table里面有比较好的方法,也欢迎分享给博主。


- (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了!


完整的代码








你可能感兴趣的:(动画,布局,ios开发,UITableView)