Возможно ли разработать подклассы NSCell в Interface Builder?

Я пытаюсь подклассифицировать NSCell для использования в NSTableView. Ячейка, которую я хочу создать, довольно сложна, поэтому было бы очень полезно, если бы я мог ее создать в Interface Builder, а затем загрузить NSCell из низа.

Возможно ли это? Как это сделать?

Ответ 1

Вопрос был о подклассе NSCell; другие ответы, похоже, делают что-то еще, вероятно, используя UITableViewCell, являющийся представлением.

NSCell - это не представление. Хотя закладка пользовательской ячейки в IB была бы полезной, чтобы быть в состоянии сделать, я думаю, что ответ в основном "нет, это невозможно". Когда вы подклассе NSCell, вы в значительной степени просто делаете свой собственный рисунок. Существует не поддержка subcells, или параметризованная автоматическая компоновка (ala NSView springs и struts), что я подозреваю, что вы ищете.

Единственное предостережение заключается в том, что вы можете создать подкласс NSCell, который сделал макет субэлементов и предоставил параметры для настройки этих подэлементов и всех настраиваемых параметров. Затем вам нужно будет написать плагин IB, чтобы сделать эту ячейку и сопровождающий инспектор доступным во время разработки в IB.

Однако это, вероятно, сложнее, чем писать небольшое пользовательское приложение, которое делает более или менее одно и то же. Поместите NSCell в элемент управления посередине окна и сделайте себе интерфейс для настройки параметров, которые вам интересны. Привязки могут сделать это довольно простым для позиционирования материала (т.е. Привязать значение x к слайдеру), хотя вы будете не получить прямое управление элементами, конечно. Когда вы закончите, вы можете архивировать свою ячейку и загружать архив во время выполнения в реальном приложении, или вы можете просто выйти из свойств и установить их в коде в своем приложении.

Ответ 2

Некоторые ответы в этой теме исчезли из-за того, что они говорят о Cocoa Touch, когда исходный вопрос был о Cocoa - в этом отношении два API-интерфейса сильно отличаются друг от друга, а Cocoa Touch упрощает потому что UITableViewCell является подклассом вида. NSCell нет, и что проблема

Для информации мне пришлось сделать что-то очень похожее в NSOutlineView в последнее время - это в основном то же самое, но немного сложнее, если что-то, потому что вам приходится иметь дело с раскрытием/срывом уровней. Если вас интересует код, я разместил его здесь: http://www.stevestreeting.com/2010/08/08/cocoa-tip-using-custom-table-outline-cells-designed-in-ib/

НТН

Ответ 3

Как говорит Кен, NSCells и NSViews различаются, и вы можете размещать иерархии NSView только в NIB, а не NSCells (которые не имеют явной иерархии).

С другой стороны, ничто не мешает вам иметь иерархию NSViews и использовать это, чтобы нарисовать ваш NSCell - вы могли бы добавить их в качестве подсмотра родительского представления вашей ячейки, сообщить им для отображения и удалите их из окна, и никто не станет мудрее.

В этом случае использование NIB будет работать, хотя это похоже на тонну хлопот. Обычно я только что заменил объект, который принимает NSCells с пользовательским, который принимает мой NSViews, но это означает, что вы можете написать свой собственный код обработки мыши, который очень обидчив.

С другой стороны, мой подход позволяет привязывать значения представлений в NIB, поэтому вам не нужно выполнять какую-либо дополнительную работу, а это круто.

Ответ 4

В IB запустите пустой XIB. Теперь перейдите в палитру и перетащите ее в UITableViewCell, дважды щелкните, чтобы открыть и отредактировать.

включает только пользовательский UITableViewCell (нет других UIViews или других элементов верхнего уровня) - убедитесь, что он является реальным UITableViewCell в IB, или вы не можете установить идентификатор повторного использования (в отличие от литья UIView в IB как ваш пользовательский класс UITableViewCell), Затем вы можете добавить в ячейку ярлыки или что угодно, а также установить идентификатор повторного использования или установить любой индикатор раскрытия, который вам может понравиться.

Чтобы использовать, вы предоставляете такой код в таблицеView: cellForRow: atIndexPath: method:

YourCustomCellClass *cell = (YourCustomCellClass *)[tableView dequeueReusableCellWithIdentifier:<IDYouSetInXIBFile>];
if ( cell == nil )
{
        NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:<YourXIBName> owner:self options:nil];
    id firstObject = [topLevelObjects objectAtIndex:0];
    if ( [ firstObject isKindOfClass:[UITableViewCell class]] )
        cell = firstObject; 
    else cell = [topLevelObjects objectAtIndex:1];
}

Если у вас есть метки или другие элементы управления, которые вы хотите ссылаться в своем коде, подключите их в IB к своему пользовательскому классу ячеек - НЕ к владельцу файла, который вам никогда не нужно устанавливать с использованием вышеуказанного кода (вы можете оставить это как NSObject).

Изменить: я замечаю, что вы действительно ищете ответ NSCell, но подход кода к использованию IB должен быть идентичным в Cocoa с помощью кода Cocoa Touch, который я использовал выше, поскольку loadNibNamed является стандартным вызовом Cocoa.

Ответ 5

Joar Wingfors написал статью для Stepwise несколько лет назад по соответствующей теме Subviews в рядах TableView.

Основной метод - создать NSCell, который может разместить NSView. Если бы вы это сделали, тогда вы могли бы создать подкласс NSView в Interface Builder, который вы могли бы внедрить в любом месте, где вам нужна эта конкретная ячейка.

Другая возможность, если вы можете настроить Leopard, - это посмотреть, нужно ли вам использовать NSTableView или использовать NSCollectionView. Представления коллекции напрямую рассматриваются в терминах "представления элементов", а не в ячейках, поэтому они гораздо проще разрабатывать в Interface Builder.

Ответ 6

Я нашел несколько интересных примеров, которые я не совсем понимаю.

Последние 2 примера работают с NSTableViewDataSource и NSTableViewDelegate. Я хотел бы использовать Bindings a ArrayController в InterfaceBuilder для подключения других элементов пользовательского интерфейса, таких как текстовые поля.

Ответ 7

Я делаю это так:

/* example of a silly way to load a UITableViewCell from a standalone nib */

+ (CEntryTableViewCell *)cell
{
// TODO -- this is really silly.
NSArray *theObjects = [[NSBundle mainBundle] loadNibNamed:@"EntryTableViewCell" owner:self options:NULL];
for (id theObject in theObjects)
    if ([theObject isKindOfClass:self])
        return(theObject);
NSAssert(NO, @"Could not find object of class CEntryTableViewCell in nib");
return(NULL);
}

Однако это не очень эффективно, и если вы загружаете много данных, это может повредить вам. Конечно, вы должны использовать reuseIdentifier, который должен заставить этот код запускать только несколько раз за таблицу.

Ответ 8

1) Создайте NSViewController TableViewCell.h

2) Создайте в TableViewCell.h некоторые процедуры, например

-(void)setText:(NSString *)text image:(NSImage *)image

3) В главном классе #import "TableViewCell.h"

4) В основном классе в -(NSView *)tableView:viewForTableColumn:row: write:

NSImage *img = //some image
TableViewCell *cell = [[TableViewCell alloc] initWithWindowNibName:@"TableViewCell"];
cell.view.init;
[cell setText:@"some text" image:img];
return cell;

Надеюсь, это поможет =)

Ответ 9

Я хочу предложить более современный подход здесь.

Начиная с iOS 5, UITableView имеет метод

(void)registerNib:(UINib *)nib forCellReuseIdentifier:(NSString *)identifier

После регистрации вашего NIB, содержащего вашу ячейку, просто используйте

- (id)dequeueReusableCellWithIdentifier:(NSString *)identifier

чтобы получить новую ячейку. Если ячейка доступна для повторного использования, она будет возвращена, в противном случае новая ячейка будет автоматически создана, и в этом случае это означает, что она загружена из файла NIB.

Ответ 10

Добавьте UITableViewCell в свой tableviewcontroller и объявите свойство IBOutlet:

@interface KuguTableViewController : UITableViewController {
    IBOutlet UITableViewCell *customTypeCell;
}

@property (readonly)  UITableViewCell *customTypeCell;

... затем в cellForRowAtIndexPath вы можете просто использовать свою ячейку и установить ее для повторного использования:

static NSString *CellIdentifier = @"CustomCell"
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
        cell = customTypeCell;
        cell.reuseIdentifier = CellIdentifier;