【问题标题】:Using NSTableView Animations with Bindings将 NSTableView 动画与绑定一起使用
【发布时间】:2012-11-12 13:23:54
【问题描述】:

我有一个绑定到NSArrayControllerNSTableViewNSArrayControllercontentSet 属性绑定到 NSMutableSet。一切都很好。

现在我想使用NSTableView 内置的动画来删除行。我可以用- [NSTableView removeRowsAtIndexes:withAnimation:] 做到这一点,并且该行很快就会动画化,但是我从tableview 中删除的对象仍然挂在支持tableview 的NSMutableSet 中。显然我需要删除它。如果我尝试通过NSArrayControllerremoveObject: 方法将其删除,那么该对象会立即从tableview 中消失,这意味着动画不会发生或在中途被切断。

绑定可以创造奇迹并使事情变得如此简单,但是当同时使用绑定和NSTableView 动画时,保持数据源和 tableview 同步的正确方法到底是什么?答案还应该解决如何使用动画向绑定的NSTableView 添加行。

【问题讨论】:

  • 一种可能的方法是继承NSArrayController 并覆盖添加和删除方法以通知您的表格视图将删除/添加/移动哪个对象/索引。不完全确定这是否可行。
  • 我不这么认为,因为在 NSArrayController 子类中仍然需要调用 [super removeObject:] 这将立即从 NSTableView 中删除相应的行并导致任何动画被抑制.
  • Carter:好吧,您必须保留一个单独的包含内容的数组,只需使用NSArrayController 作为信号来根据需要更新您自己的内容。我实在想不出办法。
  • @Carter 我在四处寻找时看到的证据是,目前还不可能,尽管它可能会在操作系统的未来迭代中可用。同时,您可以使用的替代方法可能是NSCollectionView,它确实在使用绑定时支持动画。但是,我认为,如果说使用 NSCollectionView 会引入你必须解决的一系列问题,那就太轻描淡写了。
  • 能不能用nsarray代替nsmutableset,然后先调用[tableview removeRow...],然后从数组中同索引删除对象?

标签: objective-c cocoa nstableview


【解决方案1】:

从 cmets 中的讨论到您的问题,似乎没有一个简单的“绑定”适当的答案。因此,作为一种解决方法,您不能在开始动画后立即发出一个简单的“performSelector:withObject:afterDelay”命令吗?显然,延迟时间将近似于动画记录的方式,并且在选择器中,您从 NSMutableSet 中删除对象。

【讨论】:

  • 在发布我的问题之前,这实际上是我实施的方法,它适用于删除对象,但据我所知,在尝试为行设置动画时这是不可能的。
【解决方案2】:

我刚刚在 OS X 10.9 上玩过这个,似乎对我来说一切正常。 这是我的代码(我的基于视图的表的每一行都有一个“-”按钮:

- (IBAction)removeRow:(id)sender {
    NSUInteger selectedRow = [self.myTable rowForView:sender];
    if (selectedRow == -1) {
        return;
    }
    [self.myTable removeRowsAtIndexes:[NSIndexSet indexSetWithIndex:selectedRow] withAnimation:NSTableViewAnimationSlideUp];
    [self.myArrayHookedUpToTheNSArrayController removeObjectAtIndex:selectedRow];
}

也许在 10.9 中发生了一些变化?所有这些都是从主线程运行的,这可能是为什么? (您是否尝试过在 dispatch_async(dispatch_get_main_queue(), block()) 中调用代码?

【讨论】:

    【解决方案3】:

    当您从 NSTableView 中删除项目时,您还应该更新您的 mutableSet 变量。当你从 mutableSet 中移除项目时,你需要告诉 NSArrayController 更新。为此

    [self willchangeValueForKey:@"mutableSet"]; //your mutableset variable Name
    [self.myTable removeRowsAtIndexes:[NSIndexSet indexSetWithIndex:selectedRow] withAnimation:NSTableViewAnimationSlideUp];
    [mutableSet removeObject:item];
    [self didchangeValueForKey:@"mutableSet"];
    

    【讨论】:

      【解决方案4】:

      发现自己处于同样的境地:想要尽可能多地使用绑定(尽量减少胶水代码的数量)并且仍然能够添加特定于我的应用程序的小块逻辑。

      我有一个 NSTableView,它在其每一行上都显示了一个删除按钮。删除按钮连接到我的 NSViewController 子类上的 IBAction。该表已正确绑定到 NSArrayController(通过 IB 在我的 Storyboard 中完成)。我还想要一个关于删除行的动画。

      我正在使用 swift(但我认为将其转换为 Objective-c 应该非常简单)。我让它与绑定一起工作的唯一方法是使用计时器来推迟从 NSArrayController 中删除对象(使用下面的半秒延迟 - 更改它以满足您的需要):

      import Cocoa
      
      class ProjectsController: NSViewController {
      
          @IBOutlet var arrayController: NSArrayController!
          @IBOutlet weak var tableView: NSTableView!
      
          @IBAction func deleteRow( object: AnyObject ) {
              let row = tableView.rowForView( object as! NSView )
              if ( row > -1 ) {
                  let indexSet = NSIndexSet( index:row )
                  tableView.removeRowsAtIndexes( indexSet, withAnimation: NSTableViewAnimationOptions.EffectFade )
                  NSTimer.scheduledTimerWithTimeInterval( 0.5, target: self, selector: "rowDeleted:", userInfo: row, repeats: false )
              }
          }
      
          func rowDeleted( timer:NSTimer ) {
              let row = timer.userInfo as! Int
              arrayController.removeObjectAtArrangedObjectIndex( row )
          }
      }
      

      【讨论】:

        【解决方案5】:

        模型需要在动画完成后立即更新:

        @IBAction func onRemoveClick(sender: AnyObject?) {
            let selection = listController.selectionIndexes
            NSAnimationContext.runAnimationGroup({
                context in
                self.tableView.removeRowsAtIndexes(selection, withAnimation: .EffectFade | .SlideUp)
            }, completionHandler: {
                self.listController.removeObjectsAtArrangedObjectIndexes(selection)
            })
        }
        

        在我的应用程序中使用绑定。在 OS X 10.9、10.10 和 10.11 上测试。

        【讨论】:

          【解决方案6】:

          Big Sur 有一些更新。要获得流畅的动画,必须使用NSAnimationContext。在没有它的情况下运行NSTableView 将重新加载其所有数据。

          - (IBAction)delete:(nullable id)sender
          {
              NSIndexSet *indexSet = [self.tableView indexesToProcessForContextMenu];
              [NSAnimationContext runAnimationGroup:^(NSAnimationContext * _Nonnull context) {
                  context.allowsImplicitAnimation = YES;
                  [self.tableView removeRowsAtIndexes:indexSet withAnimation:NSTableViewAnimationEffectFade | NSTableViewAnimationSlideUp];
              } completionHandler:^{
                  [self.resultsArrayController removeObjectsAtArrangedObjectIndexes:indexSet];
              }];
              
              //CODE THAT CAUSES TABLE RELOAD ON BIG SUR
              //[self.tableView removeRowsAtIndexes:indexSet withAnimation:NSTableViewAnimationEffectFade | NSTableViewAnimationSlideUp];
              //[self.resultsArrayController removeObjectsAtArrangedObjectIndexes:indexSet];
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2016-06-30
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-05-15
            • 2013-06-18
            相关资源
            最近更新 更多