Выделение выделения в NSCollectionView - PullRequest
32 голосов
/ 30 марта 2010

У меня есть рабочий 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 делегата выбора нет, и, в отличие от большинства представлений пользовательского интерфейса Какао, по умолчанию нет выделенного выделения.

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

  1. Как мне получить выбранный предмет?
  2. Как показать выделение элемента?
Похоже, что руководства по программированию

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

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

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

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

Обновление 1

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

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

В пробуждении от Nib

[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
            }
        }
    }

Не забудьте сдать deloc для не-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

Ответы [ 9 ]

33 голосов
/ 31 января 2011

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

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

Я пытался прикрепить скриншоты Интерфейсного Разработчика, но я был отклонен, потому что я новичок: - (

25 голосов
/ 30 марта 2010

Это не так сложно сделать. Убедитесь, что «Выбор» включен для NSCollectionView в Интерфейсном Разработчике. Затем в подклассе NSView, который вы используете для представления прототипа, объявите свойство с именем «selected»:

@property (readwrite) BOOL selected;

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

Подкласс NSCollectionViewItem и переопределение -setSelected:

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

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

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

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

3 голосов
/ 09 декабря 2013

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

В вашем подклассе переопределить 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 в Интерфейсном Разработчике.

2 голосов
/ 02 марта 2015

Поскольку ни один из существующих ответов не работал для меня очень хорошо, вот мое мнение. Измените подкласс элемента 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];
}
1 голос
/ 20 февраля 2019

В вашем подклассе 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
    }
  }
}
1 голос
/ 13 мая 2014

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

enter image description here

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

Установите путь к ключу модели как selected, а для преобразователя значения - NSNegateBoolean. Теперь все, что выбрано для отдельных ячеек / элементов, будет видно изображение, отсюда и выбор.

Добавление к ответу Альтера.

Чтобы установить NSBox в качестве корневого элемента. Просто создайте новый документ IB (скажем, CollectionItem) и перетащите NSBox в пустую область. Теперь добавьте все элементы, как требуется внутри коробки. Теперь нажмите на владельца файла и установите пользовательский класс как NSCollectionViewItem.

enter image description here

И в наконечнике, куда добавлено NSCollectionView, измените имя наконечника на CollectionViewItem

enter image description here

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

enter image description here

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

enter image description here

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

0 голосов
/ 31 января 2019

Вот полный Swift NSCollectionViewItem с выбором. Не забудьте установить NSCollectioView для выбора в IB или программно.

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
}
}
0 голосов
/ 15 октября 2018

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

class MyViewItem: NSCollectionViewItem {
  override var isSelected: Bool {
      didSet {
        self.view.layer?.backgroundColor = (isSelected ? NSColor.blue.cgColor : NSColor.clear.cgColor)
      }
  }
  etc...
}
0 голосов
/ 02 февраля 2011

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

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

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

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

...