"Oompa loompa doompety doo,
I’ve got a perfect puzzle for you"

Repetir até encaixar

Renan Nery
Android Dev BR
Published in
4 min readApr 29, 2016

--

Recentemente me deparei com uma situação onde o layout proposto era uma imagem que se repetia por várias vezes em uma linha horizontal

Na minha visão são triângulos cinzas repetidos

Comecei a pensar em como fazer essa tela, o meu primeiro teste foi usando o atributo android:tileMode=”repeat” dentro de um drawable bitmap, o resultado final não me agradou, mas senti que eu estava chegado lá e com pouco código!

Drawable bitmap aplicado no ImageView

Perceba que o último triângulo ficou cortado no final, isso acontece pois o tileMode não da "resize" do elemento que será repetido.

Bom, acabei tendo que pensar um pouco mais, dai fiz umas continhas e cheguei em algumas premissas.

  1. Os triângulos devem ser repetidos até preencher o layout pai (no caso esse retângulo vermelho), vamos assumir parentLayoutWidth.
  2. A imagem do triângulo tem um comprimento X, esse X depende do tamanho da imagem que for repetida, vamos assumir triangleWidth.
  3. Logo eu tenho que saber quantos triangleWidth cabem dentro de parentLayoutWidth.

Seguindo essas premissas cheguei no seguinte código:

int parentLayoutWidth, triangleWidth;

parentLayoutWidth = linearLayout.getWidth();
triangleWidth = imageView.getWidth();

int qtdTriangle = (int) Math.round((double) parentLayoutWidth / (double) triangleWidth);
int newTriangleWidth = parentLayoutWidth / qtdTriangle;

LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(newTriangleWidth, imageView.getHeight());

int trianglesSumWidth = newTriangleWidth * qtdTriangle;
int diff = parentLayoutWidth - trianglesSumWidth;

Temos então 6 variáveis

  • parentLayoutWidth: Comprimento do layout pai.
  • triangleWidth: Comprimento do triângulo.
  • qtdTriangle: Aqui já sabemos quantos triângulos vão caber.
  • newTriangleWidth: Este será o novo comprimento do triângulo, calculado pela divisão do parentLayoutWidth / qtdTriangle.
  • trianglesSumWidth: Soma do comprimento total com todos os triângulos.
  • diff: Como utilizamos valores inteiros arredondados, vai acabar dando uma diferença entre o valor de trianglesSumWidth e parentLayoutWidth, essa diferença eu guardo para aplicar entre os triângulos repetidos. Aqui é onde fica o pulo do gato do "resize".

Explicada a teoria, vamos a prática ver o que resulta toda essa parada:

Valores encontrados rodando em um Samsung Galaxy S6

Teremos então 18 triângulos completos, porém o diff deu 16 pixels, e agora?

Esse diff é o que causa o corte no final da repetição, sabendo disso eu vou pegar esse diff e distribuir entre os triângulos, como vai ser coisa de apenas 1 pixel a mais no comprimento do triângulo, o resultado final nem parece que existe essa diferença entre eles.

Por fim temos que fazer um loop que vai adicionar em tempo de execução esses triângulos, chegando aqui fica fácil:

for (int i = 0; i < qtdTriangle; i++) {
ImageView ivTriangle = new ImageView(getApplicationContext());
ivTriangle.setImageResource(R.drawable.triangle_1);
ivTriangle.setLayoutParams(layoutParams);

int plusPixel = diff > 0 ? 1 : 0;

LinearLayout.LayoutParams triangleLayoutParams = new LinearLayout.LayoutParams(newTriangleWidth + plusPixel, imageView.getHeight());
ivTriangle.setScaleType(ImageView.ScaleType.FIT_XY);
ivTriangle.setColorFilter(plusPixel == 1 ? Color.GREEN : Color.WHITE);
ivTriangle.setLayoutParams(triangleLayoutParams);

linearLayout.addView(ivTriangle);

diff--;
}

Repare que no laço da quantidade de triângulos eu vou decrementando o valor de diff, dai quando chegar a zero nenhum pixel será somado no comprimento do triângulo respectivo.

Beleza, e como ficou esse POC? Veja só.

Samsung Galaxy S6 (Portrait)
Samsung Galaxy S6 (Landscape)
  • O triângulo solitário no topo eu uso ele como "view de referência", pois quando ele inflar no layout já terei todas as medidas deste ImageView para a densidade do dispositivo.
  • A segunda linha horizontal com os triângulos brancos é o resultado usando tileMode="repeat"
  • Por último e não menos importante, a terceira linha já é usando o código de repetição de views maroto. Os triângulos verdes são os que tiveram 1 pixel adicionado em seu comprimento, já os brancos continuam como vieram ao mundo.

Bacana? O final dessa novela toda ficou um layout muito, muito parecido como que me foi proposto, coloquei até uma sombrinha com gradient para ficar mais legal ainda.

Não se engane, o triângulo repetido é BRANCO e não cinza!

--

--