问题
i work with swift for osx. I have a nstableview (one row, one column) with a custom cell view. in the storyboard i have "designed" two different row layouts with identifiers CellLayout1 and CellLayout2
func numberOfRows(in tableView: NSTableView) -> Int {
return dataArray.count
}
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
let view = tblPositions.make(withIdentifier: "CellLayout1", owner: nil) as! CustomCell
view.txtName.stringValue = dataArray[row]
return view
}
now i would like to show the CellLayout2, if i click on a row i use this function to check if the selection is changing:
func tableViewSelectionDidChange(_ notification: Notification) {
// ?
}
but now i don't know, how can i show the CellLayout2 for the selected row. can anybody help me? :)
UPDATE
var selectedRow = Int()
func numberOfRows(in tableView: NSTableView) -> Int {
return dataArray.count
}
func tableView(_ tableView: NSTableView, heightOfRow row: Int) -> CGFloat {
if selectedRow == row {
return 200
} else {
return 60
}
}
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
if selectedRow == row {
let view = tableView.make(withIdentifier: "CellLayout1", owner: nil) as! CustomCell
return view
}
let view = tableView.make(withIdentifier: "CellLayout2", owner: nil) as! CustomCell
return view
}
func tableViewSelectionDidChange(_ notification: Notification) {
selectedRow = tblPositions.selectedRow
tblPositions.reloadData()
//tblPositions.reloadData(forRowIndexes: tblPositions.selectedRowIndexes, columnIndexes: tblPositions.selectedColumnIndexes)
}
this way works nearly perfect - but:
the layout only changes if I reload the complete table. this code does not take any effect:
//tblPositions.reloadData(forRowIndexes: tblPositions.selectedRowIndexes, columnIndexes: tblPositions.selectedColumnIndexes)
.if i select a row, the tableview reload the data, the layout will change, but the selected row will deselected. this should not happen.
回答1:
To do a good MVC it should go like this.
- on cell click you are updating data model. For example change flag.
- model should trigger notification for that change
your controller should observe model, and when notification was received that item was changed, you should pass this notification to a table view:
tableView.func reloadData(forRowIndexes: rowsToUpdate columnIndexes: colmnToUpdate)
table view will reload cell for given index
- it will invoke again
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int)
where you are providing cell which matches item flag.
When using Array
as a data model than KVO
can be used.
From some of my projects I have a good example how controller can look like. It is in Objective C, but should be helpful:
static char dummy = 0;
static NSString * const kImageCellsId = @"ImageCellView";
static NSString * const kDescriptionCellId = @"DescriptionCellView";
@interface CommonImagesViewController () <NSTableViewDataSource, NSTabViewDelegate>
@property (nonatomic, strong) IBOutlet NSTableView *tableView;
@property (nonatomic, strong) CommonImagesHandler *imageHandler;
@end
@implementation CommonImagesViewController
- (void)dealloc {
[self.imageHandler removeObserver: self
forKeyPath: kCommonImagesHandlerImageCollectionKey
context: &dummy];
}
- (void)viewDidLoad {
[super viewDidLoad];
self.imageHandler = ClientManager.getInstance.imageHandler;
[self.imageHandler addObserver: self
forKeyPath: kCommonImagesHandlerImageCollectionKey
options: (NSKeyValueObservingOptions)0
context: &dummy];
[self.tableView reloadData];
}
#pragma mark - NSTableViewDataSource
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
{
return (NSInteger)self.imageHandler.imageCollection.count;
}
#pragma mark - NSTabViewDelegate
- (nullable NSView *)tableView: (NSTableView *)tableView
viewForTableColumn: (nullable NSTableColumn *)tableColumn
row: (NSInteger)row
{
ImageData *item = self.imageHandler.imageCollection[(NSUInteger)row];
if (tableColumn == tableView.tableColumns[0]) {
NSTableCellView *cell = (NSTableCellView *)[self.tableView makeViewWithIdentifier: kImageCellsId owner: nil];
cell.imageView.image = item.image;
cell.textField.stringValue = item.userDesc;
return cell;
}
return nil;
}
#pragma mark - actions
- (IBAction)deleteAllEntries:(id)sender
{
[self.imageHandler clearImageCollection];
}
- (IBAction)deleteSelected:(id)sender
{
NSIndexSet *indexes = self.tableView.selectedRowIndexes;
[self.imageHandler removeImageCollectionAtIndexes: indexes];
}
- (IBAction)viewImage:(id)sender
{
// TODO:
}
#pragma mark - KVO
- (void)observeValueForKeyPath: (NSString *)keyPath
ofObject: (id)object
change: (NSDictionary *)change
context: (void *)context
{
if (context == &dummy) {
if (self.imageHandler == object && [keyPath isEqualToString: kCommonImagesHandlerImageCollectionKey]) {
NSIndexSet *indexSet = change[NSKeyValueChangeIndexesKey];
if (indexSet.count == 0) {
return;
}
NSKeyValueChange changeType = (NSKeyValueChange)[change[NSKeyValueChangeKindKey] integerValue];
switch (changeType) {
case NSKeyValueChangeSetting:
[self.tableView reloadDataForRowIndexes: indexSet
columnIndexes: [NSIndexSet indexSetWithIndex: 0]];
break;
case NSKeyValueChangeInsertion:
[self.tableView insertRowsAtIndexes: indexSet withAnimation: NSTableViewAnimationSlideLeft];
break;
case NSKeyValueChangeRemoval:
[self.tableView removeRowsAtIndexes: indexSet withAnimation: NSTableViewAnimationSlideRight];
break;
case NSKeyValueChangeReplacement:
[self.tableView reloadData];
break;
}
}
} else {
[super observeValueForKeyPath: keyPath
ofObject: object
change: change
context: context];
}
}
@end
Where self.imageHandler
points to my data model, which contains array with full implemented support for KVO.
来源:https://stackoverflow.com/questions/45357639/change-custom-view-cell-on-click