Использование анимации NSTableView с привязками
У меня есть NSTableView
, связанный с NSArrayController
. Свойство NSArrayController
contentSet
привязано к NSMutableSet
. Все отлично работает.
Теперь я хочу использовать анимации, встроенные в NSTableView
, для удаления строк. Я могу сделать это с помощью - [NSTableView removeRowsAtIndexes:withAnimation:]
, и строка быстро анимируется, однако объект, который я удалил из tableview, все еще висит в NSMutableSet
, который поддерживает табличное представление. Очевидно, мне нужно удалить его. Если я попытаюсь удалить его с помощью метода NSArrayController
removeObject:
, тогда объект немедленно исчезнет из таблицы, что означает, что анимация не возникает или отключается на полпути.
Привязки творят чудеса и делают вещи намного проще, но что именно является правильным методом для хранения источника данных и таблицы в синхронизации, когда используются как привязки, так и анимация NSTableView
? В ответе также должно быть рассмотрено, как добавить строки в связанный NSTableView
с помощью анимаций.
Ответы
Ответ 1
Модель должна быть обновлена сразу после завершения анимации:
@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.
Ответ 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, который предоставляет кнопку удаления на каждой из своих строк. Кнопка удаления подключена к IBAction в моем подклассе NSViewController. Таблица должным образом привязана к NSArrayController (выполняется в моей раскадровке через IB). Мне также нужна анимация при удалении строки.
Я использую 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
Кажется, из обсуждения в комментарии к вашему вопросу, что нет простого "привязки" соответствующего ответа. Таким образом, вы можете просто создать простую команду "performSelector: withObject: afterDelay" сразу после запуска анимации? Очевидно, что время задержки будет приблизительным, как журнал принимает анимацию, а в селекторе - это место, где вы удаляете объект из NSMutableSet.