Estou tentando fazer algo um pouco elaborado, mas algo que deve ser possível. Então, aqui está um desafio para todos os especialistas por aí (este fórum é um pacote para muitos de vocês :)).
Estou criando um "componente" do questionário, que quero carregar em um NavigationContoller
(meu QuestionManagerViewController
). O "componente" é um "vazio" UIViewController
, que pode carregar visualizações diferentes, dependendo da pergunta que precisa ser respondida.
O jeito que eu faço é:
- Crie o objeto Question1View como uma
UIView
subclasse, definindo algunsIBOutlets
. - Crie (usando o Interface Builder) o
Question1View.xib
(AQUI ESTÁ ONDE É PROVAVELMENTE MEU PROBLEMA ). Defino oUIViewController
e oUIView
da classe Question1View. - Eu vinculo as saídas com o componente da visualização (usando IB).
Eu substituo o
initWithNib
meuQuestionManagerViewController
para ficar assim:- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { if (self = [super initWithNibName:@"Question1View" bundle:nibBundleOrNil]) { // Custom initialization } return self; }
Quando executo o código, estou recebendo este erro:
14-05-2009 15: 05: 37.152 iMobiDines [17148: 20b] *** Finalizando o aplicativo devido a uma exceção não detectada '
NSInternalInconsistencyException
', motivo: '-[UIViewController _loadViewFromNibNamed:bundle:]
carregou a ponta "Question1View", mas a saída de exibição não estava definida.'
Tenho certeza de que existe uma maneira de carregar a exibição usando o arquivo nib, sem a necessidade de criar uma classe viewController.
fonte
Obrigado a todos. Eu encontrei uma maneira de fazer o que eu queria.
UIView
com o queIBOutlet
você precisa.UIViewController
(nenhuma subclasse personalizada, mas a "real"). A visualização do proprietário do arquivo está conectada à visualização principal e sua classe é declarada como a da etapa 1).IBOutlet
s.O
DynamicViewController
pode executar sua lógica para decidir qual view / xib carregar. Uma vez feita a decisão, noloadView
método coloque algo como isto:É isso aí!
O
loadNibNamed
método do pacote principal cuidará de inicializar a exibição e criar as conexões.Agora, o ViewController pode exibir uma visualização ou outra, dependendo dos dados da memória, e a tela "pai" não precisa se preocupar com essa lógica.
fonte
Não tenho certeza do que algumas das respostas estão falando, mas preciso colocar essa resposta aqui para quando pesquisar no Google na próxima vez. Palavras-chave: "Como carregar um UIView de uma ponta" ou "Como carregar um UIView de um NSBundle".
Aqui está o código quase 100% direto do livro Apress Beginning iPhone 3 (página 247, "Usando a nova célula de exibição de tabela"):
Isso supõe que você tenha uma
UIView
subclasse chamadaBlah
, uma ponta chamadaBlah
que contém umUIView
cuja classe foi definidaBlah
.Categoria: NSObject + LoadFromNib
Extensão rápida
E um exemplo em uso:
fonte
isKindOf
você está protegido contra alterações na estrutura do Bundle.assert
seria provavelmente uma solução melhor. Dessa forma, você apenas ocultará o problema.for
loop. Isso complementa.Para todos aqueles que precisam gerenciar mais de uma instância da visualização personalizada, ou seja, uma coleção de saída , mesclei e personalizei as respostas @Gonso, @AVeryDev e @Olie desta maneira:
Crie um personalizado
MyView : UIView
e configure-o como " Classe Personalizada " da raizUIView
no XIB desejado ;Crie todos os pontos de venda de que você precisa
MyView
(faça-o agora porque, após o ponto 3, o IB proporá que você conecte os pontos deUIViewController
vista à exibição personalizada, e não à vista personalizada);Defina seu
UIViewController
como " Proprietário do arquivo " da visualização personalizada XIB ;No
UIViewController
adicionar um novoUIViews
para cada instânciaMyView
que você quer, e conectá-los aUIViewController
criar um Outlet Collection : esses pontos de vista irá funcionar como pontos de vista "wrapper" para as instâncias de exibição personalizado;Finalmente, nas
viewDidLoad
do seuUIViewController
add seguintes linhas os:fonte
Eu usaria o UINib para instanciar um UIView personalizado a ser reutilizado
Os arquivos necessários neste caso são MyCustomView.xib , MyCustomViewClass.h e MyCustomViewClass.m Observe que
[UINib instantiateWithOwner]
retorna uma matriz, portanto, você deve usar o elemento que reflete o UIView que deseja reutilizar. Nesse caso, é o primeiro elemento.fonte
Você não deve definir a classe do seu controlador de exibição como uma subclasse
UIView
no Interface Builder. Definitivamente, isso é pelo menos parte do seu problema. Deixe isso como umaUIViewController
subclasse ou outra classe personalizada que você possui.Como para carregar apenas uma visão de um xib, eu estava sob o pressuposto de que você tinha que ter algum tipo de controlador de vista (mesmo que não se estende
UIViewController
, o que pode ser muito pesado para as suas necessidades) Definir como proprietário do arquivo na interface Construtor, se você quiser usá-lo para definir sua interface. Eu fiz uma pequena pesquisa para confirmar isso também. Isso ocorre porque, caso contrário, não haveria maneira de acessar qualquer um dos elementos da interface noUIView
, nem haveria uma maneira de ter seus próprios métodos no código acionados por eventos.Se você usar a
UIViewController
como Proprietário do arquivo para suas visualizações, poderá usáinitWithNibName:bundle:
-lo para carregá-lo e recuperar o objeto do controlador de visualização. No IB, certifique-se de definir aview
tomada para a visualização com sua interface no xib. Se você usar algum outro tipo de objeto como o Dono do arquivo, precisará usarNSBundle
oloadNibNamed:owner:options:
método de para carregar a ponta, passando uma instância do Dono do arquivo para o método. Todas as suas propriedades serão definidas corretamente de acordo com as saídas definidas no IB.fonte
Você também pode usar o initWithNibName do UIViewController em vez de loadNibNamed. É mais simples, eu acho.
Agora você só precisa criar MySubView.xib e MySubView.h / m. No MySubView.xib, defina a classe Proprietário do arquivo como UIViewController e visualize a classe como MySubView.
Você pode posicionar e tamanho do
subview
arquivo xib pai.fonte
Esta é uma ótima pergunta (+1) e as respostas foram quase úteis;) Desculpe, pessoal, mas passei um tempo passando por isso, apesar de Gonso e AVeryDev terem dado boas dicas. Felizmente, esta resposta ajudará outras pessoas.
MyVC
é o controlador de exibição que contém todas essas coisas.MySubview
é a visão que queremos carregar de um xibMySubView
com o tamanho e a forma corretos e posicionados onde desejar.Em MyVC.h, tenha
No MyVC.m,
@synthesize mySubView;
e não se esqueça de liberá-lo nodealloc
.UIView *view
(pode ser desnecessária, mas funcionou para mim.) Sintetize e libere-a em .mMySubview
e vincule a propriedade view à sua view.IBOutlet
aos desejadosDe volta ao MyVC.m, tenha
O mais complicado para mim foi: as dicas nas outras respostas carregaram minha visualização do xib, mas NÃO substituíram a visualização no MyVC (duh!) - tive que trocar isso sozinho.
Além disso, para obter acesso aos
mySubview
métodos de, aview
propriedade no arquivo .xib deve ser definida comoMySubview
. Caso contrário, ele volta como simplesUIView
.Se há uma maneira de carregar
mySubview
diretamente do seu próprio xib, isso seria ótimo, mas isso me levou aonde eu precisava estar.fonte
Isso é algo que deveria ser mais fácil. Acabei estendendo
UIViewController
e adicionando umloadNib:inPlaceholder:
seletor. Agora eu posso dizerAqui está o código da categoria (ele faz o mesmo rigamarole descrito por Gonso):
fonte
Em rápido
Na verdade, minha resolução para esse problema foi carregar a visualização em um viewDidLoad no meu CustonViewController onde eu queria usar a visualização dessa maneira:
Não carregue a visualização em um
loadView()
método! O método loadView serve para carregar a visualização do seu ViewController personalizado.fonte
Eu também queria fazer algo semelhante, foi o que encontrei: (SDK 3.1.3)
Eu tenho um controlador de exibição A (de propriedade de um controlador Nav) que carrega o VC B em um pressionamento de botão:
No AViewController.m
Agora, o VC B tem sua interface do Bnib, mas quando um botão é pressionado, quero ir para um 'modo de edição' que possui uma interface de usuário separada de uma ponta diferente, mas não quero um novo VC para o modo de edição, Quero que a nova ponta seja associada ao meu B VC existente.
Então, em BViewController.m (no método de pressionar o botão)
Em outro botão, pressione (para sair do modo de edição):
e estou de volta ao meu Bnib original.
Isso funciona bem, mas observe que meu EditMode.nib possui apenas um objeto de nível superior, um objeto UIView. Não importa se o proprietário do arquivo nesta ponta está definido como BViewController ou o NSObject padrão, MAS certifique-se de que a saída de exibição no proprietário do arquivo NÃO esteja definida para nada. Se for, então eu recebo uma falha exc_bad_access e o xcode prossegue para carregar quadros de pilha 6677 mostrando um método UIView interno repetidamente chamado ... então parece um loop infinito. (No entanto, o View Outlet está definido no meu Bnib original)
Espero que isto ajude.
fonte
Eu fiz uma categoria que eu gosto:
UIView+NibInitializer.h
UIView+NibInitializer.m
Então, chame assim:
Use um nome de ponta se sua ponta tiver outro nome que não seja o nome da sua classe.
Para substituí-lo em suas subclasses por comportamento adicional, pode ser assim:
fonte
Para usuário Swift com opção designável:
UIView
subclasse personalizada e um arquivo xib , que nomearemos após o próprio nome da classe: no nosso caso, MemeView. Dentro da classe Meme View, lembre-se de defini-la como designável com o@IBDesignable
atributo antes da declaração da classeLembre-se de definir o Proprietário do arquivo no xib com nossa
UIView
subclasse personalizada no painel do Indetity InspectorNo arquivo xib agora podemos construir nossa interface, criar restrições, criar saídas, ações etc.
Precisamos implementar alguns métodos em nossa classe personalizada para abrir o xib uma vez inicializado
class XibbedView: UIView {
}
Em nossa classe personalizada, também podemos definir algumas propriedades inspecionáveis para ter controle total sobre elas a partir do criador de interface
@IBDesignable class MemeView: XibbedView {
}
Poucos exemplos:
Se precisarmos adicionar mais informações, a exibição enquanto é exibida dentro de um storyboard ou outro xib, para fazer isso, podemos implementar
prepareForInterfaceBuilder()
, esse método será executado apenas ao abrir o arquivo no construtor de interfaces. Se você fez tudo o que escrevi, mas nada está funcionando, é uma maneira de depurar uma exibição de sigle adicionando pontos de interrupção em sua implementação. Aqui está a hierarquia de visualizações.Espero que isso ajude uma amostra completa pode ser baixada aqui
fonte
let nib = loadNib(nibName)
esta é uma instância do XibbedView, se você chamar `` `addSubview (nib)` ``, estará adicionando uma instância do XibbedView a outra instância do XibbedView?Eu achei este post de Aaron Hillegass (autor, instrutor, Cocoa ninja) muito esclarecedor. Mesmo se você não adotar a abordagem modificada para carregar arquivos NIB por meio de um inicializador designado, provavelmente obterá pelo menos uma melhor compreensão do processo que está acontecendo. Ultimamente, tenho usado esse método com muito sucesso!
fonte
A resposta anterior não leva em consideração uma alteração na estrutura NIB (XIB) que ocorreu entre 2.0 e 2.1 do iPhone SDK. O conteúdo do usuário agora começa no índice 0 em vez de 1.
Você pode usar a macro 2.1 que é válida para toda a versão 2.1 e posterior (ou seja, dois sublinhados antes do IPHONE:
Usamos uma técnica semelhante a esta para a maioria de nossas aplicações.
Barney
fonte
Eu tinha motivos para fazer a mesma coisa (carregando programaticamente uma visualização de um arquivo XIB), mas precisava fazer isso inteiramente a partir do contexto de uma subclasse de uma subclasse de a
UIView
(isto é, sem envolver o controlador de exibição de nenhuma maneira). Para fazer isso, criei este método utilitário:Então eu chamo isso do
initWithFrame
método da minha subclasse da seguinte forma:Publicado para interesse geral; se alguém encontrar algum problema sem fazê-lo dessa maneira, informe-me.
fonte
Aqui está uma maneira de fazê-lo no Swift (atualmente escrevendo o Swift 2.0 no XCode 7 beta 5).
Na sua
UIView
subclasse que você definiu como "Classe personalizada" no Interface Builder, crie um método como este (minha subclasse é chamada RecordingFooterView):Então você pode simplesmente chamar assim:
let recordingFooterView = RecordingFooterView.loadFromNib()
fonte
Nenhuma das respostas explica como criar o XIB independente que é a raiz desta pergunta. Não há
Xcode 4
opção para "Criar novo arquivo XIB".Para fazer isso
Isso pode parecer simples, mas pode economizar alguns minutos, pois a palavra "XIB" não aparece em lugar algum.
fonte
@AVeryDev
6) Para anexar a vista carregada à vista do seu controlador de vista:
Presumivelmente, é necessário removê-lo da exibição para evitar vazamentos de memória.
Para esclarecer: o controlador de exibição possui vários IBOutlets, alguns dos quais estão conectados aos itens no arquivo de ponta original (como de costume), e alguns estão conectados aos itens na ponta carregada. Ambas as pontas têm a mesma classe de proprietário. A vista carregada sobrepõe a vista original.
Dica: defina como zero a opacidade da vista principal na ponta carregada, para não ocultar os itens da ponta original.
fonte
Depois de passar muitas horas, formei a seguinte solução. Siga estas etapas para criar personalizado
UIView
.1) Crie a classe myCustomView herdada do UIView .
2) Crie .xib com o nome myCustomView .
3) Altere a classe do UIView dentro do seu arquivo .xib, atribua a classe myCustomView lá.
4) Crie IBOutlets
5) Carregue .xib no myCustomView * customView . Use o seguinte código de exemplo.
fonte
Versão mais curta:
fonte
Eu tenho uma convenção de nomear xibs com exibições nelas iguais à exibição. O mesmo que se faria com um controlador de exibição. Então, não preciso escrever nomes de classe no código. Carrego um UIView a partir de um arquivo de ponta com o mesmo nome.
Exemplo para uma classe chamada MyView.
No seu código, crie um novo MyView como este:
MyView * myView = [MyView nib_viewFromNibWithOwner: owner];
Aqui está a categoria para isso:
Em seguida, conectava botões com ações do controlador que estou usando e definia as coisas nos rótulos usando as saídas na minha subclasse de exibição personalizada.
fonte
Para carregar programaticamente uma visualização de uma ponta / ponta no Swift 4:
fonte
Acabei adicionando uma categoria ao UIView para isso:
explicação aqui: o viewcontroller é menos view loading no ios e no mac
fonte