Eu quero criar uma subclasse UIView
e mostrar uma visualização como o login. Eu criei isso em Objective-C, mas agora quero portá-lo para Swift. Eu não uso storyboards, então crio toda a minha IU no código.
Mas o primeiro problema é que devo implementar initWithCoder
. Eu dei a ele uma implementação padrão, já que ele não será chamado. Agora, quando executo o programa, ele trava, porque também preciso implementar initWithFrame
. Agora eu entendi:
override init() {
super.init()
println("Default init")
}
override init(frame: CGRect) {
super.init(frame: frame)
println("Frame init")
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
println("Coder init")
}
Minha pergunta é onde devo criar meu campo de texto, etc ... e se eu nunca implementar frame e coder, como posso "esconder" isso?
CGRectZero
, acredito que seja recomendado usarCGRect.zeroRect
.Isso é mais simples.
fonte
Exemplo de subclasse UIView personalizado
Normalmente crio aplicativos iOS sem usar storyboards ou pontas. Vou compartilhar algumas técnicas que aprendi para responder às suas perguntas.
Escondendo
init
métodos indesejadosMinha primeira sugestão é declarar uma base
UIView
para ocultar inicializadores indesejados. Eu discuti essa abordagem em detalhes em minha resposta a "Como ocultar inicializadores específicos de storyboard e Nib em subclasses de IU" . Observação: esta abordagem pressupõe que você não usaráBaseView
seus descendentes em storyboards ou pontas, pois isso fará com que o aplicativo trave intencionalmente.Sua subclasse UIView personalizada deve ser herdada de
BaseView
. Ele deve chamar super.init () em seu inicializador. Não é necessário implementarinit(coder:)
. Isso é demonstrado no exemplo abaixo.Adicionando um UITextField
Eu crio propriedades armazenadas para subvisualizações referenciadas fora do
init
método. Eu normalmente faria isso para um UITextField. Eu prefiro subviews instanciar dentro da declaração da propriedade subexibição assim:let textField = UITextField()
.O UITextField não estará visível a menos que você o adicione à lista de subvisualização da visualização personalizada chamando
addSubview(_:)
. Isso é demonstrado no exemplo abaixo.Layout programático sem layout automático
O UITextField não ficará visível a menos que você defina seu tamanho e posição. Costumo fazer layout em código (não usando Auto Layout) dentro do método layoutSubviews .
layoutSubviews()
é chamado inicialmente e sempre que ocorre um evento de redimensionamento. Isso permite ajustar o layout dependendo do tamanho de CustomView. Por exemplo, se CustomView aparece na largura total em vários tamanhos de iPhones e iPads e se ajusta para rotação, ele precisa acomodar muitos tamanhos iniciais e redimensionar dinamicamente.Você pode consultar
frame.height
eframe.width
emlayoutSubviews()
para obter as dimensões do CustomView para referência. Isso é demonstrado no exemplo abaixo.Exemplo de subclasse UIView
Uma subclasse UIView personalizada contendo um UITextField que não precisa ser implementado
init?(coder:)
.Layout programático com layout automático
Você também pode implementar layout usando Layout automático no código. Como não faço isso com frequência, não mostrarei um exemplo. Você pode encontrar exemplos de implementação de Layout automático em código no Stack Overflow e em outros lugares na Internet.
Estruturas de layout programático
Existem estruturas de código aberto que implementam layout no código. Um no qual estou interessado, mas não tentei, é o LayoutKit . Foi escrito pela equipe de desenvolvimento do LinkedIn. Do repositório Github: "O LinkedIn criou o LayoutKit porque descobrimos que o Auto Layout não tem desempenho suficiente para hierarquias de visualização complicadas em visualizações com rolagem."
Por que colocar
fatalError
eminit(coder:)
Ao criar subclasses de UIView que nunca serão usadas em um storyboard ou bico, você pode introduzir inicializadores com diferentes parâmetros e requisitos de inicialização que não podem ser chamados pelo
init(coder:)
método. Se você não reprovou o init (coder :) com umfatalError
, isso poderia levar a problemas muito confusos no futuro se usado acidentalmente em um storyboard / bico. O fatalError afirma essas intenções.Se você deseja executar algum código quando a subclasse é criada, independentemente de ser criado no código ou em um storyboard / nib, você pode fazer algo como o seguinte (com base na resposta de Jeff Gu Kang )
fonte
fatalError
você proíbe de iniciar esta visão com arquivos xibfatalError
dentro do método dealloc e nos dizer que ele não funciona porque essa classe deve ser um singleton. Se você preferir criar elementos de IU no código, não deve proibir manualmente todas as outras maneiras. Finalmente, a questão é como criar "programaticamente sem storyboards", mas xibs / nibs não são mencionados. No meu caso, preciso criar um array de células com programaticamente + xib e passá-los paraDropDownMenuKit
e desta forma não funciona porque o autor desta biblioteca proíbe o xibs também.É importante que seu UIView possa ser criado por construtor de interface / storyboards ou a partir de código. Acho útil ter um
setup
método para reduzir a duplicação de qualquer código de configuração. por exemplofonte
Swift 4.0, se você deseja usar a visualização do arquivo xib, então isto é para você. Criei a classe CustomCalloutView Subclasse de UIView. Eu criei um arquivo xib e em IB apenas selecione o proprietário do arquivo, selecione o inspetor de atributos, defina o nome da classe para CustomCalloutView e crie uma saída em sua classe.
// Agora adicionando
fonte
Aqui está um exemplo de como normalmente construo minhas subclasses (UIView). Eu tenho o conteúdo como variáveis para que eles possam ser acessados e ajustados talvez mais tarde em alguma outra classe. Também mostrei como uso o layout automático e adição de conteúdo.
Por exemplo, em um ViewController eu tenho esta visão inicializada em ViewDidLoad (), uma vez que só é chamada uma vez quando a visão está visível. Então eu uso essas funções que crio aqui
addContentToView()
e entãoactivateConstraints()
para construir o conteúdo e definir restrições. Se eu posteriormente em um ViewController quiser que a cor de, digamos, um botão seja vermelho, eu apenas faço isso naquela função específica naquele ViewController. Algo como:func tweaksome(){ self.customView.someButton.color = UIColor.red}
fonte