Выбор выделения в 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
Ответы
Ответ 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
}
}