According to Apple's documentation on [NSTableViewDelegate tableView:shouldEditTableColumn:row:]
, "this method is only valid for NSCell-based table views". What's its equivalent for view-based table views? I would like to replace the default inline-editing with a custom editing experience.
Commenting on Astoria's approach:
The inconvient "problem" with having to change the editability of the text field whenever the editability of the model changes, is that you have to "actively" track the editibility of the model and update the text field's editability.
By contrast, the cell-based table view's delegate approach defers caring about editability until the very moment the user attempts to make an edit, at which point the delegate simply returns whether the model can be edited or not. There's a lot less setup, and a less potential for making a mistake. (eg, depending on how you're monitoring/responding to editability in the model, you may miss a change and now the user can incorrectly edit or not edit the field.)
So a different approach is to recreate the delegation of determining editability at the moment the user attempts to edit. To do this, you'd subclass NSTextField
, override the "right spot", ask the delegate, and allow or disallow editablity.
The "right spot" would seem to be overriding acceptsFirstResponder
, and returning NO.
- (BOOL)acceptsFirstResponder
{
BOOL accepts = [super acceptsFirstResponder];
if (accepts) {
if ([self.delegate respondsToSelector:@selector(textFieldShouldBecomeEditable:)]) {
accepts = [self.delegate textFieldShouldBecomeEditable:self];
}
}
return accepts;
}
With the above, as long as the field's editable
is YES, the delegate is called to have final determination.
Depending on your application, this may be a more desirable approach because monitoring changes to the model's editability is not straight forward. However, generally, the standard approach of simply setting the field's editable
property is best.
There's actually no need in this delegate method with view-based table views.
In that case you need to create, for example, some NSView-subclass. There may be nib-file too.
Let's say, you have a class named CustomCellView having some outlets. CustomCellView.h
file
#define kCustomCellViewReusableIdentifier @"kCustomCellViewReusableIdentifier" // NSTableView reuses cell views
@interface CustomCellView : NSView
@property (weak) IBOutlet NSImageView *imageView;
@property (weak) IBOutlet NSTextField *textField;
- (void)setCellEditable:(BOOL)editable;
@end
Here's your CustomCellView.m
file
@implementation CustomCellView
- (void)awakeFromNib
{
// paste your ui initializing code here
}
- (void)prepareForReuse
{
// this method will call each time cell reuses
}
- (void)setCellEditable:(BOOL)editable
{
[self.textField setEditable:editable];
// some other code
}
@end
Don't forget to create nib-file and connect your outlets. Your NSTableView owner class must have some initializing code for reusing. MyTableViewController.m
- (void)initUI
{
NSString *nibName = NSStringFromClass([CustomCellView class]);
[self.tableView registerNib:[[NSNib alloc] initWithNibNamed:nibName bundle:nil]
forIdentifier:kCustomCellViewReusableIdentifier];
}
#pragma mark - table view data source methods
- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{
CustomCellView *view=[tableView makeViewWithIdentifier:kCustomCellViewReusableIdentifier owner:nil];
[view setCellEditable:someCondition]; //
return view;
}
#pragma mark - operations
- (void)setViewAtColumn:(NSTableColumn *)tableColumn row:(NSInteger)row editable:(BOOL)editable
{
CustomCellView *view=[self.tableView viewAtColumn:tableColumn row:row makeIfNecessary:NO]; //no need to create it if it's not exists - we'll set the data in NSTableViewDataSource method
if (view) // if it's exists
[view setCellEditable:editable];
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With