Solução original
- Criei um XIB e uma classe chamada SomeView (usei o mesmo nome para conveniência e legibilidade). Baseei ambos em um UIView.
- No XIB, alterei a classe "Proprietário do arquivo" para SomeView (no inspetor de identidade).
- Criei uma saída UIView em SomeView.swift, vinculando-a à visualização de nível superior no arquivo XIB (chamada de "visualização" por conveniência). Em seguida, adicionei outras saídas a outros controles no arquivo XIB, conforme necessário.
- em SomeView.swift, carreguei o XIB dentro do inicializador "init com código". Não há necessidade de atribuir nada ao "eu". Assim que o XIB é carregado, todas as tomadas são conectadas, incluindo a visualização de nível superior. A única coisa que falta é adicionar a vista superior à hierarquia da vista:
.
class SomeView: UIView {
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
NSBundle.mainBundle().loadNibNamed("SomeView", owner: self, options: nil)
self.addSubview(self.view); // adding the top level view to the view hierarchy
}
...
}
Note que desta maneira eu recebo uma classe que se carrega da ponta. Eu poderia usar o SomeView como uma classe sempre que o UIView pudesse ser usado no projeto (no construtor de interfaces ou programaticamente).
Atualização - usando a sintaxe do Swift 3
O carregamento de um xib na seguinte extensão é gravado como um método de instância, que pode ser usado por um inicializador como o descrito acima:
extension UIView {
@discardableResult // 1
func fromNib<T : UIView>() -> T? { // 2
guard let contentView = Bundle(for: type(of: self)).loadNibNamed(String(describing: type(of: self)), owner: self, options: nil)?.first as? T else { // 3
// xib not loaded, or its top view is of the wrong type
return nil
}
self.addSubview(contentView) // 4
contentView.translatesAutoresizingMaskIntoConstraints = false // 5
contentView.layoutAttachAll(to: self) // 6
return contentView // 7
}
}
- O uso de um valor de retorno descartável, pois a visualização retornada não interessa mais ao chamador quando todas as tomadas já estiverem conectadas.
- Este é um método genérico que retorna um objeto opcional do tipo UIView. Se não conseguir carregar a visualização, ele retornará nulo.
- Tentativa de carregar um arquivo XIB com o mesmo nome que a instância de classe atual. Se isso falhar, nada será retornado.
- Incluindo a visualização de nível superior na hierarquia da visualização.
- Esta linha assume que estamos usando restrições para o layout da exibição.
- Esse método adiciona restrições superiores, inferiores, iniciais e finais - anexando a exibição a "auto" em todos os lados (consulte https://stackoverflow.com/a/46279424/2274829 para obter detalhes)
- Retornando a visualização de nível superior
E o método de chamada pode ser assim:
final class SomeView: UIView { // 1.
required init?(coder aDecoder: NSCoder) { // 2 - storyboard initializer
super.init(coder: aDecoder)
fromNib() // 5.
}
init() { // 3 - programmatic initializer
super.init(frame: CGRect.zero) // 4.
fromNib() // 6.
}
// other methods ...
}
- SomeClass é uma subclasse UIView que carrega seu conteúdo de um arquivo SomeClass.xib. A palavra-chave "final" é opcional.
- Um inicializador para quando a visualização é usada em um storyboard (lembre-se de usar SomeClass como a classe personalizada da visualização do storyboard).
- Um inicializador para quando a exibição é criada programaticamente (ou seja: "deixe myView = SomeView ()").
- Usando um quadro com todos os zeros, já que essa visualização é organizada usando o layout automático. Observe que o método "init (frame: CGRect) {..}" não é criado independentemente, pois o layout automático é usado exclusivamente em nosso projeto.
- & 6. Carregando o arquivo xib usando a extensão.
Crédito: O uso de uma extensão genérica nesta solução foi inspirado na resposta de Robert abaixo.
Editar
Alterando "view" para "contentView" para evitar confusão. Também alterou o subscrito da matriz para ".first".
File's Owner
chegar ao local ... Obrigado!fromNib()
de dentroinit(coder aDecoder: NSCoder)
cria um ciclo infinito como o carregamento da ponta no interior dofromNib()
método faz uma chamada para:init(coder aDecoder: NSCoder)
Minha contribuição:
Então chame assim:
..ou mesmo:
fonte
Agora, poder retornar
-> Self
rapidamente ajuda a simplificar um pouco isso. Última confirmação em Swift 5.Se seu
.xib
arquivo e subclasse compartilharem o mesmo nome, você poderá usar:Se você tiver um nome personalizado, use:
NOTA:
Se você estiver recebendo o erro "visualização do tipo YourType não encontrada em ..", não definiu a classe da visualização no
.xib
arquivoSelecione sua visualização no
.xib
arquivo, pressionecmd + opt + 4
e, naclass
entrada, insira sua classefonte
let myCustomView = UIView.fromNib() as? CustomView
. Neste caso,T.self
resolveUIView
, em vez deCustomView
e ele não consegue encontrar a ponta. Não sei por que isso é - talvez o tipo inferido para oslet
meios pelos quais a função é chamada como aUIView
?tente seguir o código.
Editar:
fonte
Extensões de protocolo Swift 4
Adoção
Esta implementação assume que o Nib tem o mesmo nome que a classe UIView. Ex. MyView.xib. Você pode modificar esse comportamento implementando nibName () no MyView para retornar um nome diferente do que a implementação da extensão de protocolo padrão.
No xib, o proprietário dos arquivos é MyView e a classe de visualização raiz é MyView.
Uso
fonte
Consegui isso com o Swift pelo seguinte código:
Não se esqueça de ligar o seu XIB vista tomada a vista tomada definido na rápida. Você também pode definir o Primeiro Respondente como seu nome de classe personalizado para começar a conectar quaisquer tomadas adicionais.
Espero que isto ajude!
fonte
Testado no Xcode 7 beta 4, Swift 2.0 e iOS9 SDK. O código a seguir atribuirá o xib à uiview. Você pode usar essa visualização xib customizada no storyboard e acessar também o objeto IBOutlet.
Acesse customview programaticamente
Código fonte - https://github.com/karthikprabhuA/CustomXIBSwift
fonte
Se você tiver muitas visualizações personalizadas em seu projeto, poderá criar classes como
UIViewFromNib
Swift 2.3
Swift 3
E em todas as classes herdadas
UIViewFromNib
, também é possível substituir anibName
propriedade se o.xib
arquivo tiver um nome diferente:fonte
Com base nas soluções acima.
Isso funcionará em todos os pacotes configuráveis do projeto e não haverá necessidade de genéricos ao chamar fromNib ().
Swift 2
Swift 3
Pode ser usado assim:
Ou assim:
fonte
Swift 4
Não esqueça de escrever ".primeiro como? CustomView".
Se você quiser usar em qualquer lugar
A melhor solução é a resposta de Robert Gummesson .
Então chame assim:
fonte
fonte
self
é implicitamente retornado de todos osinit
métodos ...Uma boa maneira de fazer isso com o Swift é usar um enum.
Em seu código, você pode simplesmente usar:
fonte
Eu prefiro esta solução (com base na resposta se @ GK100):
No SomeView.swift, carreguei o XIB dentro do
init
ouinit:frame: CGRect
inicializador. Não há necessidade de atribuir nada ao "eu". Assim que o XIB é carregado, todas as tomadas são conectadas, incluindo a visualização de nível superior. A única coisa que falta é adicionar a vista superior à hierarquia da vista:fonte
Versão Swift 3 da resposta de Logan
fonte
Aqui está uma maneira clara e declarativa de carregar programaticamente uma exibição usando um protocolo e extensão de protocolo (Swift 4.2):
E você pode usar isso assim:
Algumas considerações adicionais :
Custom Class
conjunto (e saídas / ações definidas a partir daí), não o do Proprietário do Arquivo.fonte
Eu apenas faço desta maneira:
Este exemplo usa a primeira visualização na ponta "MyView.xib" no pacote principal. Mas você pode variar o índice, o nome da ponta ou o pacote (principal por padrão).
Eu costumava despertar visualizações no método view init ou criar métodos genéricos, como nas soluções acima (que são inteligentes por sinal), mas não faço mais isso.
Dessa forma, posso usar layouts ou características diferentes, mantendo a mesma lógica e código de exibição.
Acho mais fácil deixar um objeto de fábrica (geralmente o viewController que usará o view) criá-lo conforme necessário. Às vezes você precisa de um proprietário (geralmente quando a visualização criada tem uma tomada conectada ao criador), às vezes não.
É provavelmente por isso que a Apple não incluiu um
initFromNib
método em sua classe UIView ...Para dar um exemplo ao nível do solo, você não sabe como nasceu. Você acabou de nascer. Assim são os pontos de vista;)
fonte
Tudo o que você precisa fazer é chamar o método init no seu
UIView
classe.Faça assim:
Agora, se você deseja adicionar essa visualização como uma subvisualização no controlador de exibição, faça o mesmo no arquivo controller.swift da exibição:
fonte
Semelhante a algumas das respostas acima, mas uma extensão Swift3 UIView mais consistente:
O que oferece a conveniência de poder carregar a classe a partir de uma ponta denominada nib, mas também de outras nibs / pacotes configuráveis.
fonte
Você pode fazer isso via storyboard, basta adicionar restrições apropriadas para visualização. Você pode fazer isso facilmente subclassificando qualquer visualização, digamos
BaseView
:Objetivo-C
Swift 4
Eu forneço 2 variantes como adicionar restrições - uma comum e dentro da linguagem de formato visual - selecione a que desejar :)
Além disso, por padrão, assumiu que o
xib
nome tem o mesmo nome que o nome da classe de implementação. Se não - apenas mudexibName
parâmetro.Se você subclassificar sua visualização de
BaseView
- você pode facilmente colocar qualquer visualização e especificar a classe no IB.fonte
fonte
Versão mais poderosa baseada na resposta de Logan
E você pode usar como
fonte
A implementação mais conveniente. Aqui você precisa de dois métodos, para retornar diretamente ao objeto da sua classe, não o UIView.
Exemplo:
fonte
Se você deseja que a subclasse Swift UIView seja totalmente independente e tenha a capacidade de ser instanciada usando init ou init (quadro :) sem expor os detalhes de implementação do uso de uma Nib, é possível usar uma extensão de protocolo para conseguir isso. Esta solução evita a hierarquia UIView aninhada, conforme sugerido por muitas das outras soluções.
fonte
fonte
Eu prefiro a extensão abaixo
A diferença entre essa e a extensão mais respondida é que você não precisa armazenar uma constante ou variável.
fonte
fonte