在顶部插入行时保持uitableview静态

Dea*_*ith 60 iphone uitableview uiscrollview uikit

我有一个tableView,我在顶部插入行.

虽然我这样做,但我希望当前视图保持完全静止,因此只有向上滚动时才会显示行.

我已经尝试保存底层UIScrollview的当前位置并在插入行之后重置位置,但这导致抖动,上下,尽管它最终返回到同一位置.

有没有一个很好的方法来实现这一目标?

更新:我使用的是beginUpdate,然后是insertRowsAtIndexPath,endUpdates.没有reloadData调用.

scrollToRowAtIndexPath跳转到当前单元格的顶部(在添加行之前保存).

我试过的另一种方法,最终以正确的速度结束,但有一个颤抖的是.

save tableView currentOffset. (Underlying scrollView method)
Add rows (beginUpdates,insert...,endUpdates) 
reloadData ( to force a recalulation of the scrollview size )
Recalculate the correct new offset from the bottom of the scrollview
setContentOffset (Underlying scrollview method)
Run Code Online (Sandbox Code Playgroud)

麻烦是reloadData导致scrollview/tableview开始短暂滚动,然后setContentOffset将它返回到正确的位置.

有没有办法让tableView在没有开始显示的情况下计算出它的新尺寸?

将整个事物包装在beginAnimation commitAnimation中也没有多大帮助.

更新2:这显然可以完成 - 当您下载更新时,请参阅官方Twitter应用程序.

Ami*_*itP 48

实际上没有必要总结所有行的高度,重新加载表后的新contentSize已经表示了这一点.因此,您所要做的就是计算contentSize高度的增量并将其添加到当前偏移量.

    ...
    CGSize beforeContentSize = self.tableView.contentSize;
    [self.tableView reloadData];
    CGSize afterContentSize = self.tableView.contentSize;

    CGPoint afterContentOffset = self.tableView.contentOffset;
    CGPoint newContentOffset = CGPointMake(afterContentOffset.x, afterContentOffset.y + afterContentSize.height - beforeContentSize.height);
    self.tableView.contentOffset = newContentOffset;
    ...
Run Code Online (Sandbox Code Playgroud)

  • 不幸的是,它不适用于自动调整大小的表格——在这种情况下 contentSize 不可靠并且在添加单元格后通常会缩小。 (2认同)

小智 24

-(void) updateTableWithNewRowCount : (int) rowCount
{    
    //Save the tableview content offset 
    CGPoint tableViewOffset = [self.tableView contentOffset];                                                                                                            

    //Turn of animations for the update block 
    //to get the effect of adding rows on top of TableView
    [UIView setAnimationsEnabled:NO];

    [self.tableView beginUpdates];                    

    NSMutableArray *rowsInsertIndexPath = [[NSMutableArray alloc] init];        

    int heightForNewRows = 0;

    for (NSInteger i = 0; i < rowCount; i++) {

        NSIndexPath *tempIndexPath = [NSIndexPath indexPathForRow:i inSection:SECTION_TO_INSERT];
        [rowsInsertIndexPath addObject:tempIndexPath];

        heightForNewRows = heightForNewRows + [self heightForCellAtIndexPath:tempIndexPath];                        
    }

    [self.tableView insertRowsAtIndexPaths:rowsInsertIndexPath withRowAnimation:UITableViewRowAnimationNone];                                                                            

    tableViewOffset.y += heightForNewRows;                                                                                 

    [self.tableView endUpdates]; 

    [UIView setAnimationsEnabled:YES];

    [self.tableView setContentOffset:tableViewOffset animated:NO];           
}


-(int) heightForCellAtIndexPath: (NSIndexPath *) indexPath
{

    UITableViewCell *cell =  [self.tableView cellForRowAtIndexPath:indexPath];

    int cellHeight   =  cell.frame.size.height;

    return cellHeight;
}
Run Code Online (Sandbox Code Playgroud)

只需传入新行的行数即可插入顶部.

  • @Mayank问题是当你调用endUpdates时,行将被插入,因此它们将是可见的.然后调用setContentOffset进行调整.总的来说,这将导致短暂显示新行的闪烁. (2认同)

an0*_*an0 21

@ Dean使用图像缓存的方式实在太过分了,我认为它破坏了UI的响应能力.

一种正确的方法:使用UITableView子类并覆盖-setContentSize:在某种程度上,您可以通过某种方式计算向下推送表视图的数量,并通过设置contentOffset来抵消该视图.

这是一个最简单的示例代码,用于处理所有插入发生在表视图顶部的最简单情况:

@implementation MyTableView

- (void)setContentSize:(CGSize)contentSize {
        // I don't want move the table view during its initial loading of content.
    if (!CGSizeEqualToSize(self.contentSize, CGSizeZero)) {
        if (contentSize.height > self.contentSize.height) {
            CGPoint offset = self.contentOffset;
            offset.y += (contentSize.height - self.contentSize.height);
            self.contentOffset = offset;
        }
    }
    [super setContentSize:contentSize];
}

@end
Run Code Online (Sandbox Code Playgroud)


And*_*rev 17

有同样的问题,并找到了解决方案.

    save tableView currentOffset. (Underlying scrollView method)
    //Add rows (beginUpdates,insert...,endUpdates) // don't do this!
    reloadData ( to force a recalulation of the scrollview size )
    add newly inserted row heights to contentOffset.y here, using tableView:heightForRowAtIndexPath:
    setContentOffset (Underlying scrollview method)
Run Code Online (Sandbox Code Playgroud)

像这样:

- (CGFloat) firstRowHeight
{
    return [self tableView:[self tableView] heightForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]];
}

...
CGPoint offset = [[self tableView] contentOffset];
[self tableView] reloadData];
offset.y += [self firstRowHeight];
if (offset.y > [[self tableView] contentSize].height) {
    offset.y = 0;
}
[[self tableView] setContentOffset:offset];
...
Run Code Online (Sandbox Code Playgroud)

工作完美,没有毛刺.

  • 但是,不要忘记在调用reloadData之前更新dataSource. (2认同)
  • @yuji会是什么? (2认同)

Wal*_*ers 9

我做了一些核心数据样本项目的测试,让它静止不动,同时在顶部可见细胞上方添加新细胞.此代码需要调整屏幕上空白空间的表,但一旦屏幕填满,它就可以正常工作.

static CGPoint  delayOffset = {0.0};

- (void)controllerWillChangeContent:(NSFetchedResultsController*)controller {
    if ( animateChanges )
        [self.tableView beginUpdates];
    delayOffset = self.tableView.contentOffset; // get the current scroll setting
}
Run Code Online (Sandbox Code Playgroud)

在单元格插入点添加了此项.您可以对细胞删除进行对应减法.

    case NSFetchedResultsChangeInsert:

        delayOffset.y += self.tableView.rowHeight;  // add for each new row
        if ( animateChanges )   
            [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationNone];
        break;
Run Code Online (Sandbox Code Playgroud)

最后

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
    if ( animateChanges )   
    {
        [self.tableView setContentOffset:delayOffset animated:YES];
        [self.tableView endUpdates];
    }
    else
    {
        [self.tableView reloadData];
        [self.tableView setContentOffset:delayOffset animated:NO];
    }
}
Run Code Online (Sandbox Code Playgroud)

使用animateChanges = NO时,在添加单元格时,我看不到任何移动.

在使用animateChanges = YES进行测试时,"颤抖"就在那里.似乎单元格插入的动画与动画表格滚动的速度不同.虽然最后的结果可能会以可见单元格的确切位置结束,但整个表格似乎移动了2或3个像素,然后向后移动.

如果动画速度可以相等,它可能看起来保持不变.

但是,当我按下按钮在上一个动画完成之前添加行时,它会突然停止动画并开始下一个动画,突然改变位置.

  • 这非常有效,谢谢.注意:我更改了delayOffset.y + = self.tableView.rowHeight; To:delayOffset.y + = [self tableView:self.tableView heightForRowAtIndexPath:newIndexPath]; 处理可变的单元格高度 (2认同)

小智 5

@院长,

您可以像这样更改代码以防止动画.

[tableView beginUpdates];
[UIView setAnimationsEnabled:NO];

// ...

[tableView endUpdates];

[tableView setContentOffset:newOffset animated:NO];
[UIView setAnimationsEnabled:YES];
Run Code Online (Sandbox Code Playgroud)


Jos*_*ura -1

使用scrollToRowAtIndexPath:atScrollPosition:animated:怎么样?您应该能够仅向数据源添加一个元素,使用上述方法设置行并重新加载表...