Подтвердить что ты не робот

Выбор выделения в NSCollectionView

У меня есть рабочий NSCollectionView с одним незначительным, но критическим исключением. Получение и выделение выделенного элемента в коллекции.

У меня все это работало до Snow Leopard, но что-то, похоже, изменилось, и я не могу наложить на него свой палец, поэтому я вернул обратно NSCollectionView к базовому тесту и последовал за документацией Apple для создания NSCollectionView здесь:

http://developer.apple.com/mac/library/DOCUMENTATION/Cocoa/Conceptual/CollectionViews/Introduction/Introduction.html

Вид коллекций отлично работает после краткого руководства по началу работы. Однако в этом руководстве не обсуждается выбор, отличный от "There are such features as incorporating image views, setting objects as selectable or not selectable and changing colors if they are selected".

Используя это в качестве примера, я перешел к следующему шагу привязки контроллера массива к NSCollectionView с помощью ключа контроллера selectionIndexes, считая, что это будет связывать любой выбор, который я делаю между NSCollectionView и контроллером массива и, таким образом, отпуская уведомление KVO. Я также устанавливаю NSCollectionView для выбора в IB.

Кажется, что нет делегата выбора для NSCollectionView и в отличие от большинства представлений пользовательского интерфейса Cocoa, по-видимому, нет выделенного выделения по умолчанию.

Итак, моя проблема действительно сводится к связанной проблеме, но два разных вопроса.

  • Как я могу выделить элемент?
  • Как показать выделение элемента?

NSCollectionView Руководство по программированию, по-видимому, мало и далеко, и большинство поисков через Google, похоже, вытягивают реализации до снега Leopard или используют представление в отдельном файле XIB.

Для последнего (отдельный XIB файл для представления) я не понимаю, почему это должно быть предпосылкой, иначе я бы предположил, что Apple не включила бы представление в тот же пакет, что и элемент представления коллекции.

Я знаю, что это будет вопрос "не видно дерева для деревьев", поэтому я готов к "дох!". момент.

Как обычно, все и вся помощь очень ценятся.

Обновление 1

ОК, поэтому я решил найти выбранный элемент (ы), но еще не определил выделение. Для интересующихся при выборе выбранных элементов (при условии, что вы следуете руководству Apple):

В контроллере (в моем тестовом примере App Delegate) я добавил следующее:

В awakeFromNib

[personArrayController addObserver:self
       forKeyPath:@"selectionIndexes" 
       options:NSKeyValueObservingOptionNew
       context:nil];

Новый метод

-(void)observeValueForKeyPath:(NSString *)keyPath 
                     ofObject:(id)object
                       change:(NSDictionary *)change
                      context:(void *)context
{
    if([keyPath isEqualTo:@"selectionIndexes"])
    {
        if([[personArrayController selectedObjects] count] > 0)
        {
            if ([[personArrayController selectedObjects] count] == 1)
            {
                personModel * pm = (PersonModel *) 
                       [[personArrayController selectedObjects] objectAtIndex:0];
                NSLog(@"Only 1 selected: %@", [pm name]);
            }
            else
            {
                // More than one selected - iterate if need be
            }
        }
    }

Не забудьте сделать dealloc для не-GC

-(void)dealloc
{
    [personArrayController removeObserver:self 
                               forKeyPath:@"selectionIndexes"];
    [super dealloc];
}

Продолжайте поиск разрешения подсветки...

Обновление 2

Взял совет по макатомии, но все еще имел проблему. Публикация соответствующих методов класса, чтобы увидеть, где я ошибся.

MyView.h

#import <Cocoa/Cocoa.h>

@interface MyView : NSView {
    BOOL selected;
}

@property (readwrite) BOOL selected;

@end

MyView.m

#import "MyView.h"

@implementation MyView

@synthesize selected;

-(id)initWithFrame:(NSRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code here.
    }
    return self;
}

-(void)drawRect:(NSRect)dirtyRect
{
    NSRect outerFrame = NSMakeRect(0, 0, 143, 104);
    NSRect selectedFrame = NSInsetRect(outerFrame, 2, 2);

    if (selected)
        [[NSColor yellowColor] set];
    else
        [[NSColor redColor] set];

    [NSBezierPath strokeRect:selectedFrame];
}

@end

MyCollectionViewItem.h

#import <Cocoa/Cocoa.h>
@class MyView;

@interface MyCollectionViewItem : NSCollectionViewItem {

}

@end

"MyCollectionViewItem.m *

#import "MyCollectionViewItem.h"
#import "MyView.h"

@implementation MyCollectionViewItem

-(void)setSelected:(BOOL)flag
{

    [(MyView *)[self view] setSelected:flag];
    [(MyView *)[self view] setNeedsDisplay:YES];
}

@end
4b9b3361

Ответ 1

Это не слишком сложно сделать. Убедитесь, что для NSCollectionView в Interface Builder включен параметр "Выбор". Затем в подклассе NSView, который вы используете для своего прототипа, объявите свойство "selected":

@property (readwrite) BOOL selected;

ОБНОВЛЕННЫЙ КОД ЗДЕСЬ: (добавлен супервызов)

Подкласс NSCollectionViewItem и override -setSelected:

- (void)setSelected:(BOOL)flag
{
    [super setSelected:flag];
    [(PrototypeView*)[self view] setSelected:flag];
    [(PrototypeView*)[self view] setNeedsDisplay:YES];
}

Затем вам нужно добавить код в свой прототип view drawRect: метод для выделения выделения:

- (void)drawRect:(NSRect)dirtyRect 
{
    if (selected) {
       [[NSColor blueColor] set];
       NSRectFill([self bounds]);
    }
}

Это просто заполняет представление синим цветом, когда оно выбрано, но оно может быть настроено для выделения выделения любым способом. Я использовал это в своих приложениях, и он отлично работает.

Ответ 2

Если в качестве подсветки достаточно другого цвета фона, вы можете просто использовать NSBox в качестве корневого элемента для просмотра элементов коллекции. Заполните NSBox цветом выделения по вашему выбору. Установите NSBox в Custom, чтобы заполнить работу. Установите NSBox прозрачным.

Свяжите атрибут прозрачности NSBox с выбранным атрибутом владельца файла (элемент коллекции) Установите трансформатор значений для прозрачной привязки к NSNegateBoolean.

Я попытался подключить скриншоты построителя интерфейса, но я был отклонен bcos Я новичок: - (

Ответ 3

Вы также можете пойти другим путем, если вы не подклассифицируете NSView для своего представления protoype.

В подклассе NSCollectionViewItem переопределить setSelected:

- (void)setSelected:(BOOL)selected
{
    [super setSelected:selected];
    if (selected)
        self.view.layer.backgroundColor = [NSColor redColor].CGColor;
    else
        self.view.layer.backgroundColor = [NSColor clearColor].CGColor;
}

И, конечно же, как сказали все мудрые люди, передо мной, убедитесь, что для NSCollectionView в Interface Builder включен "Выбор".

Ответ 4

Так как ни один из существующих ответов не работал у меня хорошо, вот мой подход к нему. Измените подкласс элемента CollectionView на SelectableCollectionViewItem. Вот код. Поставляется со связующим свойством textColor для привязки текстовой метки textColor к.

@implementation SelectableCollectionViewItem

+ (NSSet *)keyPathsForValuesAffectingTextColor
{
    return [NSSet setWithObjects:@"selected", nil];
}

- (void)viewDidLoad {
    [super viewDidLoad];

    self.view.wantsLayer = YES;
}

- (void) viewDidAppear
{
    // seems the inital selection state is not done by Apple in a KVO compliant manner, update background color manually
    [self updateBackgroundColorForSelectionState:self.isSelected];
}

- (void)updateBackgroundColorForSelectionState:(BOOL)flag
{
    if (flag)
    {
        self.view.layer.backgroundColor = [[NSColor alternateSelectedControlColor] CGColor];
    }
    else
    {
        self.view.layer.backgroundColor = [[NSColor clearColor] CGColor];
    }
}

- (void)setSelected:(BOOL)flag
{
    [super setSelected:flag];
    [self updateBackgroundColorForSelectionState:flag];
}

- (NSColor*) textColor
{
    return self.selected ? [NSColor whiteColor] : [NSColor textColor];
}

Ответ 5

В моем случае мне понадобилось изображение (галочка), чтобы указать выбор объекта. Перетащите ImageWell в элемент коллекции Item. Установите нужное изображение и пометьте его как скрытое. Перейдите к инспектору привязок и привяжите скрытый атрибут к элементу коллекции.

enter image description here

(В моем случае я создал отдельный наконечник для CollectionViewItem, поэтому его привязали к владельцу файла. Если это не так, и представление Item находится в том же nib, что и CollectionView, затем привязывается к элементу коллекции Collection)

Задайте путь ключа модели как selected и преобразователь значения до NSNegateBoolean. Это теперь, когда выбраны отдельные ячейки/элементы, изображение будет видимым, что указывает на выбор.

Добавление ответа на Alter.

Установить NSBox как корневой элемент. Просто создайте новый документ IB (скажем, CollectionItem) и перетащите NSBox в пустую область. Теперь добавьте все элементы, как требуется внутри коробки. Теперь щелкните File Owner и установите Custom Class как NSCollectionViewItem.

enter image description here

И в nib, где добавлено NSCollectionView, измените имя ниба для CollectionViewItem

enter image description here

В NSBox привяжите остальные элементы к Files Owner. Для метки это будет похоже на:

enter image description here

Теперь, чтобы получить цвет подсветки, как указано в его ответе, установите желаемую комбинацию цветов в опции "Цвет заливки", установите прозрачность NSBox и привяжите атрибут прозрачности, как показано ниже:

enter image description here

Теперь, когда выбраны элементы коллекции, вы должны увидеть цвет заливки.

Ответ 6

В вашем подклассе NSCollectionViewItem переопределите isSelected и измените цвет фона слоя. Тест в MacOS 10.14 и Swift 4.2

class Cell: NSCollectionViewItem {

  override func loadView() {    
    self.view = NSView()
    self.view.wantsLayer = true
  }

  override var isSelected: Bool {
    didSet {
      self.view.layer?.backgroundColor = isSelected ? NSColor.gray.cgColor : NSColor.clear.cgColor
    }
  }
}

Ответ 7

Это было потрясающе, спасибо большое! я боролся с этим!

Чтобы уточнить для других:

 [(PrototypeView*)[self view] setSelected:flag];
 [(PrototypeView*)[self view] setNeedsDisplay:YES];

Замените PrototypeView * именем имени своего прототипа.

Ответ 8

Если вы ищите обновленное решение Swift, посмотрите этот ответ.

class MyViewItem: NSCollectionViewItem {
  override var isSelected: Bool {
      didSet {
        self.view.layer?.backgroundColor = (isSelected ? NSColor.blue.cgColor : NSColor.clear.cgColor)
      }
  }
  etc...
}

Ответ 9

Вот полный Swift NSCollectionViewItem с выбором. Не забудьте установить NSCollectioView для выбора в IB или программно. Протестировано в MacOS Mojave (10.14) и High Sierra (10.13.6).

import Cocoa

class CollectionViewItem: NSCollectionViewItem {

private var selectionColor : CGColor {
    let selectionColor : NSColor = (isSelected ? .alternateSelectedControlColor : .clear)
    return selectionColor.cgColor
}

override var isSelected: Bool {
    didSet {
        super.isSelected = isSelected
        updateSelection()
        // Do other stuff if needed
    }
}

override func viewDidLoad() {
    super.viewDidLoad()
    view.wantsLayer = true
    updateSelection()
}

override func prepareForReuse() {
    super.prepareForReuse()
    updateSelection()
}

private func updateSelection() {
    view.layer?.backgroundColor = self.selectionColor
}
}