Boas práticas com Modifiers no Jetpack Compose
Alex Felipe
Posted on June 26, 2023
Ao escrever composables é natural o uso de modificadores - Modifiers para personalizar ou adicionar comportamentos para os nossos componentes visuais.
Dado que o uso de Modifiers é intuitivo, é muito comum escrevermos códigos sem considerar algumas boas práticas que fazem muita diferença em Apps, seja para simplificar o código ou até mesmo em questões de performance...
E considerando esses detalhes, neste artigo eu vou te mostrar as técnicas que você pode utilizar para otimizar o seu código e performance com o Jetpack Compose a partir de Modifiers, bora lá?
Modifier padrão
A primeira boa prática está mais para uma convenção! O famoso Modifier padrão:
Column(Modifier.fillMaxSize()) {
Button(
onClick = { /*TODO*/ },
Modifier.fillMaxWidth()
) {
Text(
text = "button text test",
Modifier
.padding(8.dp)
.background(
Color.Gray.copy(alpha = 0.5f),
RoundedCornerShape(20.dp)
)
)
}
}
Não sei se você já notou, mas todo composable disponibilizado pela lib do Jetpack Compose ou outras libs como os do Material Design, possuem um Modifier padrão como primeiro parâmetro opcional.
O motivo dessa prática, é permitir a personalização de qualquer composable a partir de Modifiers, seja na modificação visual, eventos etc. Em outras palavras, quando criamos um composable nosso, é extremamente recomendado que exista um Modifier padrão para flexbilizar a personalização!
Adicionando um Modifier padrão
A adição do Modifier padrão exige apenas que seja o primeiro parâmetro opcional com o valor Modifier
e que modifique o primeiro Composable:
@Composable
fun MyButton(
text: String,
modifier: Modifier = Modifier
) {
Box(
modifier
.padding(8.dp)
) {
Text(
text = text,
Modifier
.align(Alignment.Center)
)
}
}
Com essa abordagem, podemos usar o mesmo botão com aparências diferentes:
Column {
MyButton("meu primeiro botão")
MyButton(
"meu segundo botão",
Modifier
.fillMaxWidth()
.padding(8.dp)
.background(Color.Gray, RoundedCornerShape(20.dp))
)
}
Essa é de longe uma das características que mais gosto do Jetpack Compose! 😎
Reutilizando o Modifier
A próxima boa prática está na reutilização de Modifiers, isso mesmo! Temos a capacidade de extrair Modifiers e reutilizá-los:
Column {
val myButtonModifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.background(Color.Gray, RoundedCornerShape(20.dp))
MyButton("meu primeiro botão")
MyButton(
"meu segundo botão",
myButtonModifier
)
Box(
modifier = myButtonModifier
.height(200.dp)
)
}
Nesta amostra, reutilizamamos a mesma aparência do segundo botão no terceiro Box
! Inclusive, note que ainda mantemos a flexibilidade para ajustar o Box
conforme a sua necessidade, como por exemplo, aplicar uma altura diferente.
Vantagens de reutilização de Modifiers
Além de reduzir a quantidade de código, a reutilização de Modifier
ajuda na otimização da recomposição, pois os Modifiers também são executados novamente nos composables afetados.
Os casos de maiores impactos são em implementações que tendem a realizar a recomposição constantemente, como a utilização de animações ou implementações lazies (LazyColumn
, LazyRow
etc).
Extração de Modifier fora do escopo de composables
Para otimizar essas situações, devemos considerar a extração de modifiers fora do escopo dos composables. Em um primeiro momento pode parecer abstrato, então vamos considerar um exemplo:
val myButtonModifier = Modifier
.padding(8.dp)
.fillMaxWidth()
.background(Color.Gray, RoundedCornerShape(20.dp))
@Composable
fun MyLazyColumn() {
LazyColumn {
items(1000) {
MyButton(
"meu segundo botão",
myButtonModifier
)
}
}
}
Sim! Apenas essa pequena extração, pode otimizar e muito implementações com recomposições frequentes! Além disso, é possível reutilizar o Modifier em outros composables, pois ele é globalmente acessível.
Extração de Modifier dentro do escopo de composables
Embora a extração de Modifier fora de escopo tenha as suas vantagens, existirão casos em que não é possível, como por exemplo, os Modifiers de escopo de composables específicos.
Os composables mais notáveis para essa situação, são os de layout como Box
, Column
ou Row
. Ambos oferecem escopos específicos que dão acesso a Modifiers exclusivos, como por exemplo o align()
que permite alinhar filhos:
@Composable
fun MyColumn() {
Column {
val myButtonModifier = Modifier
.padding(8.dp)
.width(200.dp)
.background(Color.Gray, RoundedCornerShape(20.dp))
.align(CenterHorizontally)
MyButton("meu primeiro botão")
MyButton(
"meu segundo botão",
myButtonModifier
)
Box(
modifier = myButtonModifier
.height(200.dp)
)
}
}
Uma alternativa seria extrair um novo composable apenas adicionando os Modifiers daquele escopo:
val myButtonModifier = Modifier
.padding(8.dp)
.width(200.dp)
.background(Color.Gray, RoundedCornerShape(20.dp))
@Composable
fun MyColumn() {
Column {
val myButtonColumnModifier =
myButtonModifier
.align(CenterHorizontally)
MyButton("meu primeiro botão")
MyButton(
"meu segundo botão",
myButtonColumnModifier
)
Box(
modifier = myButtonColumnModifier
.height(200.dp)
)
}
}
O que você achou dessas boas práticas com o Modifiers? Tem alguma técnica diferente que utiliza e acha interessante compartilhe, aproveite e deixe aqui nos comentários. 😉
Posted on June 26, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
January 26, 2024