Pergunta

Eu tenho um trabalho NSCollectionView com uma exceção menor, mas crítica.Obtendo e destacando o item selecionado na coleção.

Já tive tudo isso funcionando antes do Snow Leopard, mas algo parece ter mudado e não consigo identificar o que é, então peguei meu NSCollectionView voltei ao teste básico e segui a documentação da Apple para criar um NSCollectionView aqui:

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

A visualização da coleção funciona bem seguindo o guia de início rápido.No entanto, este guia não discute a seleção além de "There are such features as incorporating image views, setting objects as selectable or not selectable and changing colors if they are selected".

Usando isso como exemplo, fui para a próxima etapa de vincular o Array Controller ao NSCollectionView com a chave do controlador selectionIndexes, pensando que isso vincularia qualquer seleção que eu fizesse entre os NSCollectionView e o controlador de array e, assim, disparar uma notificação KVO.Eu também configurei o NSCollectionView ser selecionável em IB.

Parece não haver delegado de seleção para NSCollectionView e, diferentemente da maioria das visualizações da interface do usuário do Cocoa, parece não haver nenhum destaque selecionado padrão.

Portanto, meu problema realmente se resume a uma questão relacionada, mas a duas questões distintas.

  1. Como faço para capturar uma seleção de um item?
  2. Como faço para mostrar o destaque de um item?

NSCollectionViewOs guias de programação do Google parecem ser poucos e distantes entre si e a maioria das pesquisas via Google parecem extrair implementações anteriores ao Snow Leopard ou usar a visualização em um arquivo XIB separado.

Para o último (arquivo XIB separado para a visualização), não vejo por que isso deveria ser um pré-requisito, caso contrário, eu suspeitaria que a Apple não teria incluído a visualização no mesmo pacote que o item de visualização da coleção.

Eu sei que isso vai ser um problema "não posso ver a madeira para as árvores" - então estou preparado para o "DOH!" momento.

Como de costume, toda e qualquer ajuda será muito apreciada.

Atualização 1

OK, então imaginei encontrar o(s) item(s) selecionado(s), mas ainda não descobri o destaque.Para os interessados ​​em descobrir os itens selecionados (supondo que você esteja seguindo o guia da Apple):

No controlador (no meu caso de teste, o App Delegate), adicionei o seguinte:

Em acordadoFromNib

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

Novo método

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

Não se esqueça de desalocar para não-GC

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

Ainda procurando pela resolução de destaque ...

Atualização 2

Segui o conselho de Macatomy, mas ainda tive um problema.Postando os métodos de classe relevantes para ver onde errei.

Minha visualização.h

#import <Cocoa/Cocoa.h>

@interface MyView : NSView {
    BOOL selected;
}

@property (readwrite) BOOL selected;

@end

Minha visualização.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
Foi útil?

Solução

Não é muito difícil de fazer. Verifique se a "seleção" está ativada para o NScollectionView no interface Builder. Então, na subclasse NSView que você está usando para o seu protótipo Visualização, declare uma propriedade chamada "selecionada":

@property (readwrite) BOOL selected;

Código atualizado aqui: (Adicionado Super Call)

Subclasse nscollectionViewItem e substituição -setSelected:

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

Em seguida, você precisa adicionar código no método drawrect: protótipo para desenhar o destaque:

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

Isso simplesmente preenche a vista em azul quando selecionada, mas isso pode ser personalizado para desenhar o destaque da maneira que desejar. Eu usei isso em meus próprios aplicativos e funciona muito bem.

Outras dicas

Se uma cor de fundo diferente será suficiente como destaque, você poderá simplesmente usar um NSBox como o item raiz do seu item de coleta. Preencha o NSBox com a cor destacada de sua escolha. Defina o NSBox como personalizado para que o preenchimento funcione. Defina o NSBox como transparente.

Ligue o atributo de transparência do NSBox ao atributo selecionado do proprietário do arquivo (item de coleção) Defina o transformador de valor para a ligação transparente ao NSNegateBoolean.

Tentei anexar capturas de tela do Builder de interface, mas fui rejeitado BCOS, sou um novato :-(

Você também pode seguir de outra forma, se não estiver subclassificando o NSView para sua exibição Protoype.

Em sua substituição subclassem NSCOLLECTIONVELIDEM 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;
}

E, é claro, como dito por todas as pessoas sábias antes de mim, verifique se a "seleção" está ativada para o NScollectionView no interface Builder.

Como nenhuma das respostas existentes funcionou super bem para mim, aqui está a minha opinião. Altere a subclasse do item Coleção para SelectableCollectionViewItem. Aqui está seu código. Vem com uma propriedade TEXTCOLOR BINDABLE para conectar sua etiqueta de texto TEXTCOLOR LINDING para.

@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];
}

No meu caso, eu queria uma imagem (marca de seleção) para indicar a seleção do objeto. Arraste um imagewell para o item de coleção Nib. Defina a imagem desejada e marque -a como oculta. Vá para o Inspetor de Bindings e vincule um atributo oculto ao item de exibição da coleção.

enter image description here

(No meu caso, eu criei uma ponta separada para a ColeçãoViewItem, então é o proprietário do arquivo. Se esse não for o caso e a visualização do item está na mesma ponta que a Coleção, vincular ao item de visualização da coleção)

Definir o caminho da chave do modelo como selected e transformador de valor para NSNegateBoolean. É isso agora sempre que as células/itens individuais são selecionados, a imagem será visível, indicando a seleção.

Adicionando à resposta de Alter.

Para definir o NSBox como item raiz. Simplesmente crie um novo documento IB (digamos Coleção) e arraste um NSBox para a área vazia. Agora adicione todos os elementos conforme necessário dentro da caixa. Agora clique no proprietário do arquivo e defina a classe personalizada como NSCollectionViewItem.

enter image description here

E na ponta onde NSCollectionView é adicionado, altere o nome da ponta para CollectionViewItem

enter image description here

No NSBox, vincule os elementos restantes a Files Owner. Para um rótulo, seria semelhante a:

enter image description here

Agora para obter a cor destacada como Alterar mencionado em sua resposta, definir a combinação de cores desejada na opção de cor de preenchimento, defina o NSBox Para transparente e vincular o atributo de transparência como abaixo:

enter image description here

Agora, quando os itens de exibição da coleção são selecionados, você poderá ver a cor de preenchimento da caixa.

Na tua NSCollectionViewItem subclasse, substituir isSelected e altere a cor de fundo da camada. Teste no MacOS 10.14 e 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
    }
  }
}

Isso foi incrível, muito obrigado! Eu estava lutando com isso!

Para esclarecer para os outros:

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

Substitua prototyPeview* pelo nome do seu nome de classe protótipo.

Caso você esteja procurando pela solução Swift atualizada, veja esta resposta.

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

Aqui está o NSCOLLECTION COMPLETO COMPLETO com seleção. Não se esqueça de definir o NScollectioView como selecionado no IB ou programaticamente. Testado em MacOS Mojave (10.14) e 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
}
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top