Como faço para criar uma classe de visualização iOS personalizada e instanciar várias cópias dela (em IB)?
No momento, estou criando um aplicativo que terá vários temporizadores, que são basicamente iguais.
Eu quero criar uma classe personalizada que usa todo o código para os temporizadores, bem como o layout / animações, para que eu possa ter 5 temporizadores idênticos que operam independentemente um do outro.
Criei o layout usando IB (xcode 4.2) e todo o código para os temporizadores está atualmente apenas na classe viewcontroller.
Estou tendo dificuldade para entender como encapsular tudo em uma classe personalizada e, em seguida, adicioná-la ao viewcontroller, qualquer ajuda seria muito apreciada.
ios xcode class uiview uiviewcontroller
— Michael Campsall
Para qualquer um que pesquise aqui ... já se passaram cinco anos desde que as visualizações de contêiner chegaram ao iOS! As visualizações de contêiner são a ideia básica e central de como você faz tudo no iOS agora. Eles são incrivelmente simples de usar e há vários tutoriais excelentes (com cinco anos!) Sobre visualizações de contêineres, por exemplo , exemplo
@JoeBlow Exceto que você não pode usar uma visualização de contêiner em um UITableViewCellou UICollectionViewCell. No meu caso, preciso de uma visão pequena, mas bastante complexa, que possa usar muitas vezes em controladores e visualizações de coleção. E os designers continuam retrabalhando, então eu quero um único lugar onde o layout seja definido. Portanto, um bico.
Bem, para responder conceitualmente, seu cronômetro provavelmente deve ser uma subclasse de em UIViewvez de NSObject.
Para instanciar uma instância do seu temporizador no IB, simplesmente arraste e UIViewsolte-o na visualização do seu controlador de visualização e defina sua classe com o nome da classe do seu temporizador.
Lembre-se de #importsua classe de cronômetro em seu controlador de visualização.
Editar: para design IB (para instanciação de código, consulte o histórico de revisão)
Não estou muito familiarizado com o storyboard, mas sei que você pode construir sua interface em IB usando um .xibarquivo que é quase idêntico ao da versão do storyboard; Você deve até mesmo ser capaz de copiar e colar suas visualizações como um todo da interface existente para o .xibarquivo.
Para testar isso, criei um novo vazio .xibchamado "MyCustomTimerView.xib". Em seguida, adicionei uma visualização e a ela adicionei um rótulo e dois botões. Igual a:
Criei uma nova subclasse de classe Objectiva C UIViewchamada "MyCustomTimer". No meu, .xibeu defini minha classe Proprietário do arquivo como MyCustomTimer . Agora estou livre para conectar ações e tomadas como qualquer outra visualização / controlador. O .harquivo resultante tem a seguinte aparência:
O único obstáculo que falta superar é colocar isso .xibna minha UIViewsubclasse. Usar um .xibreduz drasticamente a configuração necessária. E como você está usando storyboards para carregar os cronômetros, sabemos que -(id)initWithCoder:é o único inicializador que será chamado. Então, aqui está a aparência do arquivo de implementação:
O método nomeado loadNibNamed:owner:options:faz exatamente o que parece. Ele carrega o Nib e define a propriedade "Proprietário do arquivo" como self. Extraímos o primeiro objeto do array e essa é a visão raiz do Nib. Adicionamos a visualização como uma subvisualização e Voila está na tela.
Obviamente, isso apenas muda a cor de fundo do rótulo quando os botões são pressionados, mas este exemplo deve ajudá-lo no bom caminho.
Notas baseadas em comentários:
É importante notar que, se você está tendo problemas de recursão infinita, provavelmente não percebeu o truque sutil dessa solução. Não está fazendo o que você pensa que está fazendo. A visão que é colocada no storyboard não é vista, mas em vez disso carrega outra visão como uma subvisualização. A visualização que ele carrega é a visualização definida na ponta. O "proprietário do arquivo" na ponta é aquela visão invisível. A parte legal é que essa visão invisível ainda é uma classe Objective-C que pode ser usada como uma espécie de controlador de visão para a visão que ela traz da ponta. Por exemplo, os IBActionmétodos na MyCustomTimerclasse são algo que você esperaria mais em um controlador de visualização do que em uma visualização.
Como uma observação lateral, alguns podem argumentar que isso quebra MVCe eu concordo um pouco. Do meu ponto de vista, está mais relacionado a um costume UITableViewCell, que às vezes também precisa ser parte do controlador.
É importante notar também que essa resposta foi para fornecer uma solução muito específica; crie uma ponta que pode ser instanciada várias vezes na mesma visualização em um storyboard. Por exemplo, você pode facilmente imaginar seis desses temporizadores, todos em uma tela de iPad ao mesmo tempo. Se você só precisa especificar uma visualização para um controlador de visualização que deve ser usado várias vezes em seu aplicativo, a solução fornecida por jyavenard para esta questão é quase certamente uma solução melhor para você.
— NJones
Na verdade, esta parece ser uma questão separada. Mas acho que pode ser respondido rapidamente, então aqui vai. Cada vez que você cria uma nova notificação, é uma nova notificação, mas se você precisar que eles tenham o mesmo nome, deseja adicionar algo para diferenciá-los, então use a userInfopropriedade na notificação@property(nonatomic,copy) NSDictionary *userInfo;
Recebo uma recursão infinita de initWithCoder. Alguma ideia?
— desaparecido em
Desculpe por reviver um tópico antigo, certificar- File's Ownerse de que está definido com o nome da classe resolveu meu problema de recursão infinita.
— themanatuf
Outro motivo para recursão infinita é definir a visualização raiz no xib para sua classe personalizada. Se você não quiser fazer isso, deixe como "UIView" padrão
Há apenas uma coisa que me chama a atenção sobre esta abordagem ... Não incomoda ninguém que 2 Views estejam na mesma classe agora? o arquivo original .h / .m herdando de UIView sendo o primeiro e [self addSubview:[[[NSBundle mainBundle] loadNibNamed:@"MyCustomTimerView" owner:self options:nil] objectAtIndex:0]]; adicionando o segundo UIView ... Isso parece meio estranho para mim, ninguém mais se sente da mesma maneira? Se sim, isso é algo feito pela maçã por design? Ou alguém encontrou a solução ao fazer isso?
Atualizado para Xcode 10 e Swift 4
Aqui está um guia básico. Eu originalmente aprendi muito sobre isso assistindo a esta série de vídeos no Youtube . Posteriormente, atualizei minha resposta com base neste artigo .
Adicionar arquivos de visualização personalizada
Os dois arquivos a seguir formarão sua visualização personalizada:
arquivo .xib para conter o layout
arquivo .swift como UIViewsubclasse
Os detalhes para adicioná-los estão abaixo.
Arquivo Xib
Adicione um arquivo .xib ao seu projeto (Arquivo> Novo> Arquivo ...> Interface do usuário> Exibir) . Estou chamando o meu ReusableCustomView.xib.
Crie o layout que você deseja que a exibição personalizada tenha. Como exemplo, farei um layout com a UILabele a UIButton. É uma boa ideia usar o layout automático para que as coisas sejam redimensionadas automaticamente, não importando o tamanho definido posteriormente. (Usei Freeform para o tamanho xib no inspetor de atributos para poder ajustar as métricas simuladas, mas isso não é necessário.)
Arquivo Swift
Adicione um arquivo .swift ao seu projeto (Arquivo> Novo> Arquivo ...> Código-fonte> Arquivo Swift) . É uma subclasse de UIViewe estou chamando de minha ReusableCustomView.swift.
Faça do arquivo Swift o proprietário
Volte para o arquivo .xib e clique em "Proprietário do arquivo" no esboço do documento. No Inspetor de identidade, escreva o nome do seu arquivo .swift como o nome da classe personalizada.
Adicionar código de visualização personalizada
Substitua o ReusableCustomView.swiftconteúdo do arquivo pelo seguinte código:
Certifique-se de usar a grafia correta para o nome do arquivo .xib.
Conecte os Outlets e Ações
Conecte os pontos de venda e ações ao arrastar o controle do rótulo e botão no layout xib para o código de visualização personalizada rápida.
Use sua visualização personalizada
Sua visualização personalizada está concluída agora. Tudo o que você precisa fazer é adicionar um UIViewonde quiser em seu storyboard principal. Defina o nome da classe da visualização ReusableCustomViewno Identity Inspector.
Importante não definir a classe de exibição Xib como ResuableCustomView, mas como Proprietário deste Xib. Caso contrário, você terá erro.
— RealNmae
Sim, bom lembrete. Não sei quanto tempo perdi tentando resolver problemas de recursão infinita causados ​​pela definição da visualização do Xib (em vez do Proprietário do arquivo) para o nome da classe.
@TomCalmon, refiz esse projeto no Xcode 8 com Swift 3 e o Auto Layout estava funcionando bem para mim.
Se alguém mais tiver problemas com a renderização da visualização no IB, descobri que mudar Bundle.mainpara Bundle(for: ...)resolve. Aparentemente, Bundle.mainnão está disponível em tempo de design.
— crizzis
O motivo pelo qual isso não funciona com @IBDesignable é que você não o implementou init(frame:). Depois de adicionar isso (e colocar todo o código de inicialização em alguma commonInit()função), ele funciona bem e é exibido em IB. Veja mais informações aqui: stackoverflow.com/questions/31265906/…
Resposta para controladores de visualização, não visualizações :
Existe uma maneira mais fácil de carregar um xib de um storyboard. Digamos que seu controlador seja do tipo MyClassController do qual herda UIViewController.
Você adiciona um UIViewControllerusando IB em seu storyboard; mude o tipo de classe para MyClassController. Exclua a visualização que foi adicionada automaticamente ao storyboard.
Certifique-se de que o XIB que você deseja chamar se chama MyClassController.xib.
Quando a classe for instanciada durante o carregamento do storyboard, o xib será carregado automaticamente. A razão para isso é devido à implementação padrão UIViewControllerque chama o XIB nomeado com o nome da classe.
— jyavenard
Eu aumento as visualizações personalizadas o tempo todo, mas nunca conheci esse pequeno truque para carregá-lo no storyboard. Muito apreciado!
A questão é sobre visualizações, não sobre controladores de visualização.
Adicionado título para esclarecimento, "Resposta para controladores de visualização, não visualizações:"
Não parece estar funcionando no iOS 9.1. Se eu remover a visualização criada automaticamente (padrão), ela travará após retornar do viewDidLoad do VC. Não acho que a visualização no XIB seja conectada no lugar da visualização padrão.
A exceção que estou recebendo é 'Could not load NIB in bundle: 'NSBundle </Users/me/.../MyAppName.app> (loaded)' with name 'uB0-aR-WjG-view-4OA-9v-tyV''. Observe o whacko nibName. Estou usando o nome de classe correto para o na ponta.
Esta não é realmente uma resposta, mas acho que é útil compartilhar essa abordagem.
Importe CustomViewWithXib.h e CustomViewWithXib.m para seu projeto
Crie os arquivos de visualização customizados com o mesmo nome (.h / .m / .xib)
Herdar sua classe personalizada de CustomViewWithXib
Importe CustomViewWithXib.swift para o seu projeto
Crie os arquivos de visualização personalizados com o mesmo nome (.swift e .xib)
Vá para seu arquivo xib, defina o proprietário com seu nome de classe personalizado se precisar conectar alguns elementos (para obter mais detalhes, consulte a parte Tornar o arquivo Swift o proprietário das respostas @Suragch)
É tudo, agora você pode adicionar sua visualização personalizada ao storyboard e ela será exibida :)
Você pode encontrar alguns exemplos aqui .
— HamzaGhazouani
então, como podemos adicionar iboutlet para os uicontrols de visualização
Ei @AmrAngry, para conectar as visualizações você deve fazer o 4 passo: Vá para o seu arquivo xib, em "Proprietário do arquivo" defina sua classe, e arraste e solte suas visualizações na interface tocando no toque "ctrl", eu atualizo o fonte de código com este exemplo, não hesite se você tiver alguma dúvida, espero que ajude
muito obrigado pelo seu replay, eu já faço isso, mas acho que meu problema não é nesta parte. Meu problema é adicionar um UIDatePIcker e tentar adicionar uma ação de destino para este controle do ViewController para definir e o valor do evento uiControleer é alterado, mas o método nunca é chamado / fire
@AmrAngry Eu atualizo o exemplo adicionando a visualização do seletor, pode ser que ajude você :) github.com/HamzaGhazouani/Stackoverflow/tree/master/…