【问题标题】:Best way to select a row after inserting it?插入后选择行的最佳方法?
【发布时间】:2011-09-27 10:01:45
【问题描述】:

我正在使用基于导航的 CoreData 模板开发 iOS 应用程序。 我想在插入表格视图后选择并“滚动到可见”一行。理想情况下,我想选择它,取消选择它并再次选择它,以获得一种闪烁效果。

当我使用模板提供的方法时,即:

#pragma mark - Fetched results controller delegate

- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller
{
    [self.tableView beginUpdates];
}

- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo
           atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type
{
    switch(type)
    {
        case NSFetchedResultsChangeInsert:
            [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeDelete:
            [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
            break;
    }
}

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
       atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type
      newIndexPath:(NSIndexPath *)newIndexPath
{
    UITableView *tableView = self.tableView;


    switch(type)
    {

        case NSFetchedResultsChangeInsert:
            [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationTop];
                [self.tableView selectRowAtIndexPath:newIndexPath animated:YES scrollPosition:UITableViewScrollPositionMiddle];

            break;

        case NSFetchedResultsChangeDelete:
            [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeUpdate:
            [self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
            break;

        case NSFetchedResultsChangeMove:
            [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
            [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]withRowAnimation:UITableViewRowAnimationFade];
            break;
    }
}

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{


    [self.tableView endUpdates];

}  

我有点困惑,不知道该把选择代码放在哪里。
如果我放一个
[tableView selectRowAtIndexPath:&lt;#(NSIndexPath *)#&gt; animated:&lt;#(BOOL)#&gt; scrollPosition:&lt;#(UITableViewScrollPosition)#&gt;]
进入
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller,
它选择了该行,但立即取消选择它,并且滚动也不正常。

【问题讨论】:

    标签: ios uitableview core-data


    【解决方案1】:

    在方法controller:didChangeObject:atIndexPath:forChangeType:newIndexPath: 更改此部分:

    case NSFetchedResultsChangeInsert:
       [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
       [tableView scrollToRowAtIndexPath:newIndexPath atScrollPosition:UITableViewScrollPositionMiddle animated:YES];
       insertedIndexPath = newIndexPath; //remember for selection
    break;
    

    并从 UIScrollViewDelegate 添加方法:

    - (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView {
       [self.tableView selectRowAtIndexPath:insertedIndexPath animated:YES scrollPosition:UITableViewScrollPositionNone];
    }
    

    记得添加insertedIndexPath变量。

    【讨论】:

    • 谢谢。但我偶尔会遇到这个错误。 Serious application error. Exception was caught during Core Data change processing. This is usually a bug within an observer of NSManagedObjectContextObjectsDidChangeNotification. -[UITableView scrollToRowAtIndexPath:atScrollPosition:animated:]: row (1) beyond bounds (1) for section (3). with userInfo (null)。它有时也会选择错误的行。有没有别的办法?
    • 您是否使用可折叠的部分(隐藏行)?如果是,那么您必须检查插入新行的部分是否显示行,如果不是,则不要在case NSFetchedResultsChangeInsert: 中执行任何操作,否则您将收到此错误,其他情况:检查您是否在 scrollToRowAtIndexPath 之前有 insertRowsAtIndexPaths,如果我在插入之前调用滚动然后我也得到这个错误
    • 这很好用,除非表格实际上不需要滚动。例如,如果表格已经滚动到顶部,并且插入的新行位于顶部,则永远不会调用 scrollViewDidEndScrollingAnimation。告诉 tableview 选择 controller:didChangeObject:atIndexPath:forChangeType:newIndexPath: 中的行也不起作用,因为 tableview 实际上还没有更新。一种可能的解决方法可能是检查 tableView:cellForRowAtIndexPath 以查看是否应该选择正在显示的单元格,但不是。
    • 要更新,我无法在 tableView:cellForRowAtIndexPath 中完成这项工作,所以我最终放弃了在 scrollViewDidEndScrollingAnimation 中设置选择并简单地使用 performSelector:withObject:afterDelay: 来运行一个方法来设置选择和全部更新完成后滚动位置。
    【解决方案2】:

    我解决了类似的问题。我将项目插入到表的开头,我想在之后选择它。

    步骤 1. - 创建一个开关以保持状态,如果它应该选择第一行

    @implementation MyTableViewController {
        BOOL _selectFirstRow;
    }
    

    第 2 步 - 插入时将其切换为“是”

    - (void) controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath
    {
        UITableView *tableView = self.tableView;
        switch (type) {
            case NSFetchedResultsChangeInsert:
                [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
                                 withRowAnimation:UITableViewRowAnimationFade];
                _selectFirstRow = YES;
                break;
    

    步骤 3. - 创建一个方法来选择第一行

    - (void) selectFirstTableRow
    {
        [self.tableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]
                                    animated:YES
                              scrollPosition:UITableViewScrollPositionTop];
    }
    

    步骤 4. - 在表格更新后立即调用方法来选择行

    - (void) controllerDidChangeContent:(NSFetchedResultsController *)controller
    {
        [self.tableView endUpdates];
        if (_selectFirstRow) {
            [self selectFirstTableRow];
            _selectFirstRow = NO;
        }
    }
    

    这就是所有人.. 如果您想选择不同的行,请将 newIndexPath 也存储在类参数中。就这样。我希望它会帮助你。中亚!

    【讨论】:

      【解决方案3】:

      与上面的答案基本相同,但更正了何时调用 scrollToRowAtIndexPath

      在方法controller:didChangeObject:atIndexPath:forChangeType:newIndexPath: 更改此部分:

      case NSFetchedResultsChangeInsert:
         [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]  withRowAnimation:UITableViewRowAnimationFade];
         //save new index path into your own ivar
         self.newlyInsertIndex = newIndexPath
      break;
      

      如果使用样板 FRC 代码,在表更新完成之前无法滚动到新插入的索引

      在方法- (void)controllerDidChangeContent:中执行此操作

          if (!self.changeIsUserDriven){
      
               [self.tableView endUpdates];
      
              if (self.newlyInsertedIndex){
                  //ScrollPositionNone == use least amount of effort to show cell
                  [self.tableView scrollToRowAtIndexPath:self.newlyInsertedIndex  
                  atScrollPosition:UITableViewScrollPositionNone animated:YES];
                  //cleanup
                  self.newlyInsertedIndex = Nil;
              }
          }
      

      并从 UIScrollViewDelegate 添加方法:

      - (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView {
         [self.tableView selectRowAtIndexPath:insertedIndexPath animated:YES scrollPosition:UITableViewScrollPositionNone];
      }
      

      记得添加newInsertedIndex ivar

      【讨论】:

        【解决方案4】:

        这一切都不适合我。我所做的是:

        • 当我创建一个新对象时,我记得它在一个实例变量_newInstance
        • 当对象被保存或创建被取消时,我清除它:_newInstance = nil;
        • controllerDidChangeObject我选择行:

          - (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
          {
            [self.tableView endUpdates];
          
            if (_newObject) {
              NSIndexPath *ip = [self.fetchedResultsController indexPathForObject:_newObject];
              [self.tableView selectRowAtIndexPath:ip animated:YES
                              scrollPosition:UITableViewScrollPositionMiddle];
            }
          }
          

        【讨论】:

          猜你喜欢
          • 2011-02-15
          • 2012-06-07
          • 2011-08-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-01-30
          • 1970-01-01
          相关资源
          最近更新 更多