Вопрос

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

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

  1. Как мне зафиксировать выделение элемента?
  2. Как мне показать выделенный элемент элемента?

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

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

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

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

Обновление 1

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

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

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

Не забудьте освободить место для не-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
Это было полезно?

Решение

Это не так уж сложно сделать.Убедитесь, что "Выбор" включен для NSCollectionView в Interface Builder.Затем в подклассе 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]);
    }
}

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

Другие советы

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

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

Я попытался прикрепить скриншоты Interface builder, но мне было отказано, потому что я новичок:-(

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

В вашем подклассе 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.

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

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

enter image description here

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

Задайте путь к ключу модели следующим образом 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

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

В вашем 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
    }
  }
}

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

Разъяснять другим:

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

Замените PrototypeView* именем вашего прототипа class name.

На случай, если вы ищете обновленное решение Swift, посмотрите на этот ответ.

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

Вот полный 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
}
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top