Requisitos:
O Beagle já possui alguns widgets básicos que podem ser usados para alterar a sua aplicação UI através do backend. No entanto, você pode adicionar novos componentes para fazer as views da sua aplicação fiquem “visíveis” ao Beagle e que possam também ser usadas no backend.
Abaixo temos a definição da classe do componente Box. Criada com view code em swift e possui um parâmetro title, e um evento de tap.
import UIKit
class Box: UIView {
// Class parameter.
private var title: String
// Initialization part of the class.
public init(title: String) {
self.title = title
super.init(frame: .zero)
setupView()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// Method to add component to hierarchy and pass position.
private func setupView() {
addSubview(label)
label.text = title
label.topAnchor.constraint(equalTo: topAnchor).isActive = true
label.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
label.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
label.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
}
// Component `UILabel` created.
private lazy var label: UILabel = {
let label = UILabel()
label.font = .systemFont(ofSize: 20, weight: .bold)
label.backgroundColor = .red
label.textAlignment = .center
label.textColor = .white
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
}
Para fazer seu componente nativo funcionar com o Beagle, basta criar uma struct e implementar o protocolo Widget
. Isso indica que a sua struct irá conformar com Codable
, sendo assim responsável por decodificar e codificar as propriedades que o widget expõem ao backend. Além disso, para ser um Widget
também é necessário adicionar as propriedades id: String?
, style: Style?
, accessibility: Accessibility?
e implementar o método toView.
Agora com o componente Box
crie uma struct BoxWidget que implementa o protocolo Widget
.
id: Identificador do componente
style: Atributos de estilização do componente.
accessibility: Atributos de acessibilidade do componente.
toView: Método que retorna a view do componente criado.
Temos a estrutura da struct BoxWidget
com os parâmetros title
, id
, style
, accessibility
, no método toView o componente Box
estanciado passando o parâmetro title
.
import Foundation
import UIKit
import Beagle
struct BoxWidget: Widget {
let title: String
public var id: String?
public var style: Style?
public var accessibility: Accessibility?
func toView(renderer: BeagleRenderer) -> UIView {
let boxComponent = Box(title: title)
return boxComponent
}
}
Para integrar o componente ao beagle é preciso utilizar o sizeThatFits
ou AutoLayoutWrapper
.
AutoLayoutWrapper:
O objeto calcula o tamanho levando em consideração as contraints do componente.
Se o seu componente foi construído usando AutoLayout
, o Beagle usa automaticamente o AutoLayoutWrapper
na criação da hierarquia de componentes, sendo assim não é mais necessário adicioná-lo no retorno do método toView
.
sizeThatFits:
Método para implementar sua lógica de tamanho, usado na classe do componente customizado.
override func sizeThatFits(_ size: CGSize) -> CGSize {
systemLayoutSizeFitting(size)
}
Por fim precisamos registrar nosso widget customizado no Beagle.
Logo, para registrá-lo no Beagle. basta chamar a função de registro do Coder (Dependência publica do Beagle) durante o processo de configuração do ambiente do Beagle.
O método register
pode ser chamado passando somente o tipo do componente, ou também um nome customizado para identifica-lo.
type: Tipo do componente.
named: Parâmetro para setar o nome do componente. Não é obrigatório passar. Um caso é quando o nome do componente é registrado diferente com que você criou no backend. Ele será usado na deserialização para encontrar seu componente.
Maneiras de Registrar
// 1º maneira.
coder.register(type: BoxWidget.self)
// 2º maneira.
coder.register(type: BoxWidget.self, named: "BoxWidgetComponent")
Não esqueça que para usar seu componente no BFF(Backend for Frontend) ele também tem que ser registrado no mesmo.
Caso queira entender sobre BFF click aqui
Exemplo renderizado:
Em casos em que o componente customizado contém eventos de interação com o usuario basta expor esses eventos no Widget do componente. Então suponhamos que o BoxComponent agora tem que lidar com um evento de touch:
import Foundation
import UIKit
import Beagle
struct BoxWidget: Widget {
let title: String
@AutoCodable
let onTouch: [Action]?
public var id: String?
public var style: Style?
public var accessibility: Accessibility?
func toView(renderer: BeagleRenderer) -> UIView {
let boxComponent = Box(title: title)
boxComponent.onTouch = {
renderer.controller?.execute(actions: onTouch, event: "onTouch", origin: boxComponent)
}
return boxComponent
}
}
Passo 1: adicionamos o atributo let onTouch: [Action]?
que consiste em uma lista de ações que serão executadas a partir do evento de touch.
Passo 2: supondo que o componente nativo ultilize closures para tratar eventos, então atribuimos uma closure para o evento onTouch
que chama o método execute
passando a lista de ações: renderer.controller?.execute(actions: onTouch, event: "onTouch", origin: boxComponent)
Utilize a anotação @AutoCodable
nas propriedades do tipo Action
ou ServerDrivenComponent
caso seu componente receba outro componente ou uma ação, para que o swift consiga sintetizar o inicializador init(from decoder: Decoder)
.
Em termos técnicos, o AutoCodable
é um property wrapper que implementa a lógica de serialização e deserialização polimórfica dos tipos genéricos do Beagle, dessa forma, não precisamos implementar o init(from decoder: Decoder)
, uma vez que, agora o Swift consegue sintetiza-lo, já que todas as propriedades do nosso widget conformam com Codable.
Em casos em que nosso componente customizado recebe outro componente para adiciona-lo como subview, basta adicionar um atributo no nosso widget que corresponde a esse componente filho.
Então supondo que nosso componente Box agora receba uma UIView
que será adicionada em sua hierarquia de views:
struct BoxWidget: Widget {
// Class parameter.
let title: String
@AutoCodable
let child: ServerDrivenComponent
public var id: String?
public var style: Style?
public var accessibility: Accessibility?
// toView method of interface the widget.
func toView(renderer: BeagleRenderer) -> UIView {
let child: UIView = BeagleView(child)
child.translatesAutoresizingMaskIntoConstraints = false
let boxComponent = Box(title: title, child: child)
return boxComponent
}
}
Passo 1: adicionamos o atributo let child: ServerDrivenComponent
que será o componente Server Driven.
Passo 2: transformamos o componente server driven em uma UIView, a partir da classe BeagleView: let child: UIView = BeagleView(child)
Passo 3: agora que temos a UIView passamos ela no inicializador do componente Box: Box(title: title, child: child)
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.