Executando verificação de segurança...
1

Como usar "priorities" no autolayout com UIKit

Não é novidade que quando não definimos nossas prioridades as coisas começam a ficar um pouco bagunçadas não é mesmo?! E no desenvolvimento, não é diferente. Então, bora! Vamos falar de auto layout usando UIKit. Vou te mostrar um problema muito comum e uma forma de resolvê-lo. 🚨

Esse post consiste na seguinte estrutura:

  • Por que eu preciso saber disso? 🤔
  • O que é isso? 🆘
  • E como se usa esse negócio? (Hands On) 🚀
  • Me conta mais… 📌

Por que eu preciso saber disso? 🤔

Como sabemos, no mundo IOS temos o framework UIKit que nos fornece componentes para montar o nosso layout. Nesses componentes, muitas vezes (não é sempre) vêm tamanhos já definidos (width, height ou ambos), os quais chamamos de content intrisec size e que podem ser modificados de acordo com as constraints que adicionamos para eles ou até mesmo com a variação de seus conteúdos. Por exemplo, uma UILabel pode ter o mesmo tamanho do texto definido para ela, mas nada impede que seja modificada para ter um tamanho maior ao determinarmos uma regra.

Normalmente, há também uma adequação de layout, o componente foi criado para se adaptar de forma automática em casos de não definirmos regras para eles e podem crescer ou diminuir seu tamanho natural de acordo com a sua prioridade.

É isso mesmo, lidar com layout também é uma questão de prioridade pois para se adaptar está sempre se perguntando qual a view mais importante. Mas pensa comigo, se duas views são igualmente importantes, o que acontece? É meu caro, temos um conflito ou resultados visuais inesperados.

O que é isso? 🆘

UIKit define o grau de prioridade para constraints com valores de 0 a 1000. Duas características das views que indicam o quanto o tamanho delas pode sofrer alteração (ou seja, se esses valores são altos ou baixos) são contentHuggingPriority e contentCompressionResistancePriority.

De acordo com a documentação da Apple, contentHuggingPriority é o quanto uma view pode resistir para continuar com seu tamanho natural ao invés de aumentar. E já o contentCompressionResistancePriority é o quanto uma view pode resistir para continuar com seu tamanho natural ao invés de diminuir.

E como se usa esse negócio? (Hands On) 🚀

Agora que sabemos o que são essas propriedades, vamos usá-las a nosso favor! Quero trazer um exemplo de uma UIStackView que contém duas UILabels. Como vocês bem sabem, a prioridade das labels são iguais e em casos específicos, pode nos trazer um layout que não queremos.
Para implementar este exemplo, crie um novo projeto no Xcode e adicione uma stackview horizontal com duas labels na view controller:

import UIKit

class ViewController: UIViewController {
    
    private lazy var contentStackView: UIStackView = {
        let stack = UIStackView(arrangedSubviews: [descriptionLabel, valueLabel])
        stack.translatesAutoresizingMaskIntoConstraints = false
        stack.distribution = .equalCentering
        stack.spacing = 8
        return stack
    }()
    
    private lazy var descriptionLabel: UILabel = {
        let label = UILabel()
        label.translatesAutoresizingMaskIntoConstraints = false
        label.font = .systemFont(ofSize: 12)
        label.text = "Instituição:"
    }()

    private lazy var valueLabel: UILabel = {
        let label = UILabel()
        label.translatesAutoresizingMaskIntoConstraints = false
        label.font = .boldSystemFont(ofSize: 12)
        label.text = "KN Soluções"
        return label
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        setupView()
    }

    private func setupView() {
        view.backgroundColor = .white
        view.addSubview(contentStackView)
        contentStackView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
        contentStackView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 24).isActive = true
        contentStackView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -24).isActive = true
    }

}

Centralizamos nossa stackview para melhor visualização. O resultado visual é o seguinte:

artigo-ex1

Até o momento, nada parece fora do normal, nossos textos são pequenos e a distribuição da nossa stackview se encarregou de separá-las sem que uma delas aumentasse além de seu conteúdo. Mas digamos que precisemos de uma descrição maior, onde precisaremos de uma quebra de texto como no exemplo abaixo:

 private lazy var descriptionLabel: UILabel = {
      let label = UILabel()
      label.translatesAutoresizingMaskIntoConstraints = false
      label.font = .systemFont(ofSize: 12)
      label.text = "Instituição (Nome abreviado da empresa a qual pertence ou pertenceu recentemente):"
      label.lineBreakMode = .byWordWrapping
      label.numberOfLines = .zero
      return label
 }()

O resultado de visual de nossa modificação será algo de difícil leitura:

artigo-ex2

🔍 Vamos investigar

Atualmente, ambas as labels tem prioridades iguais 250 em hugging priority e 750 em compression priority.

💡Você pode verificar esses valores usando: label.contentCompressionResistancePriority(for: .horizontal) e label.contentCompressionResistancePriority(for: .horizontal)

Não se preocupe, agora que sabemos sobre prioridades vai ficar bem mais fácil resolver este problema. Para nossa descrição iremos dizer que sua resistência em ficar menor é baixa, já que queremos que esse texto tenha seu tamanho natural. E para nosso valor, adicionaremos uma resistência em ficar maior bem alta, para evitar que seja comprimida.

☑️ Importante lembrar

Para usar essas propriedades precisamos definir duas coisas: em que eixo aplicaremos a resistência e o grau de prioridade que queremos que ela tenha. Como estamos tratando de sua largura, definiremos uma prioridade para seu eixo .horizontal e utilizaremos .defaultLow ou .defaultHigh para modificar suas prioridades para mais baixa ou mais alta, respectivamente.

 private lazy var descriptionLabel: UILabel = {
    let label = UILabel()
    label.translatesAutoresizingMaskIntoConstraints = false
    label.font = .systemFont(ofSize: 12)
    label.text = "Instituição (Nome abreviado da empresa a qual pertence ou pertenceu recentemente):"
    label.lineBreakMode = .byWordWrapping
    label.numberOfLines = .zero
    label.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
    return label
}()

 private lazy var valueLabel: UILabel = {
    let label = UILabel()
    label.translatesAutoresizingMaskIntoConstraints = false
    label.font = .boldSystemFont(ofSize: 12)
    label.text = "KN Soluções"
    label.setContentHuggingPriority(.defaultHigh, for: .horizontal)
    return label
}()

Prontinho! Agora sim temos o resultado que desejamos:

artigo-ex3

☑️ O que aconteceu com os valores de prioridade?

Nossa descriptionLabel que antes tinha sua compression priority com 750 agora passa a ter sua prioridade abaixada para 250. E nossa valuelabel que antes tinha sua hugging priority com 250 agora passa a ter sua prioridade aumentada para 750.

💡 Em muitos casos, modificar prioridade em apenas um dos objetos já traz o resultado desejado, por questões de didática e medidas preventivas utilizamos em ambos.

Tendo em vista que já falei demais, deixo aqui este resumo para complementar nosso hands on:

setContentHuggingPriority — quanto mais alta, maior resistência para crescer

setContentCompressionResistancePriority — quanto mais alta, maior resistência para encolher

Me conta mais… 📌

Nunca é demais aprender! Se você quer se aprofundar um pouco mais sugiro as leituras abaixo:

Espero ter contribuído para seus estudos! 😘

Carregando publicação patrocinada...