Concrete Logo
Hamburger button

Views customizadas no Android – Parte 2

  • Blog
  • 25 de Fevereiro de 2016
Share

*Esse post foi originalmente publicado no Medium e no Blog pessoal do autor.

No post anterior, mostramos como criar views customizadas a partir da extensão de widget e do agrupamentos de views. Hoje, veremos como é possível definir atributos customizados e utilizá-los direto do arquivo de layout que possui a view criada.

Atributos customizados

Para possibilitar que uma view seja fácil de usar e flexível, é possível criar atributos que podem ser utilizados para configurar/customizar uma view. Para exemplificar, vamos utilizar a MoneyView, que foi criada na primeira parte do post sobre views customizadas.

Na view correspondente aos valores monetários, podemos criar atributos para definir o tamanho do texto, se a cor do texto deve ser modificada quando o valor for negativo e qual cor deve ser utilizada.

Criação dos atributos

Os atributos são declarados por meio do recurso declare-styleable, que suporta a configuração de diversos atributos. Normalmente estes recursos são inseridos no arquivo @res/values/attrs.xml.

O Android permite que o atributo seja definido com os tipos abaixo:

  • integer – números inteiros (também suporta declaração hexadecimal)
  • float – números decimais
  • fraction – percentagem, n% ou n%p (relativo ao elemento-pai), onde n deve ser um número inteiro.
  • boolean – booleano (true/false)
  • reference – referência ao resource (drawables, strings, colors, layouts, etc)
  • color – referência a uma cor
  • dimension – referência a uma dimensão (dp, sp, pt, px, mm, in)
  • string – um texto ou referência a uma string
  • enum – conjunto de valores que são aceitos

Agora que já sabemos como declarar os aspectos customizáveis, vamos à implementação.

MoneyView

O primeiro passo será criar no arquivo attrs.xml os atributos: “mv_currencySize” (tamanho da fonte da moeda), “mv_valueSize” (tamanho da fonte do valor monetário), “mv_defaultColor” (cor padrão do texto), “mv_negativeColor” (cor do texto quando o valor for negativo), “mv_value” (valor monetário) e “mv_enableChangeColor” (habilitação da mudança de cor quando o valor for negativo) da MoneyView.

Para melhor organização de código é recomendado utilizar como prefixo as iniciais da classe correspondente à view customizada, pois em um projeto é comum existir diversos atributos customizados e, desta forma, conseguimos identificar facilmente a qual view aquele atributo pertence.

[code language=”xml”]
<?xml version="1.0" encoding="utf-8"?>
<resources>

<declare-styleable name="MoneyView">
<attr name="mv_currencySize" format="dimension" />
<attr name="mv_valueSize" format="dimension" />
<attr name="mv_defaultColor" format="color" />
<attr name="mv_negativeColor" format="color" />
<attr name="mv_value" format="string" />
<attr name="mv_enableChangeColor" format="boolean" />
</declare-styleable>

</resources>
[/code]

O segundo passo é adicionar no construtor da view customizada a obtenção dos valores passados nos atributos.

Essa operação é realizada com o TypedArray, que consiste em um container para o array dos parâmetros da view customizada. O TypedArray é obtido pelo método obtainStyledAttributes da classe Context do Android.

Um ponto de atenção é chamar o método recycle do TypeArray para que ele seja liberado e possa ser reutilizado posteriormente.

@MoneyView.java

[code language=”java”]
package com.tpinho.customviews.ui.custom;

import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.support.annotation.StringRes;
import android.support.v4.content.ContextCompat;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.tpinho.customviews.R;

import java.math.BigDecimal;

import br.com.concretesolutions.canarinho.formatador.FormatadorValor;

import static android.os.Build.VERSION_CODES.LOLLIPOP;

/**
* Created by tpinho on 1/4/16.
*/
public class MoneyView extends LinearLayout {

private float currencySize;
private float valueSize;

private int defaultColor;
private int negativeColor;

private boolean enableChangeColor;

private String value;

private TextView textMoneyCurrency;
private TextView textMoneyValue;

public MoneyView(Context context) {
super(context);
init();
}

public MoneyView(Context context, AttributeSet attrs) {
super(context, attrs);
initWithStyle(context, attrs);
}

public MoneyView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initWithStyle(context, attrs);
}

@TargetApi(LOLLIPOP)
public MoneyView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
initWithStyle(context, attrs);
}

private void initWithStyle(final Context context, final AttributeSet attrs) {
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MoneyView);

currencySize = typedArray.getDimensionPixelSize(R.styleable.MoneyView_mv_currencySize, getResources().getDimensionPixelSize(R.dimen.dimen_text_15_sp));
valueSize = typedArray.getDimensionPixelSize(R.styleable.MoneyView_mv_valueSize, getResources().getDimensionPixelSize(R.dimen.dimen_text_15_sp));

defaultColor = typedArray.getColor(R.styleable.MoneyView_mv_defaultColor, ContextCompat.getColor(getContext(), R.color.black));
negativeColor = typedArray.getColor(R.styleable.MoneyView_mv_negativeColor, ContextCompat.getColor(getContext(), R.color.red));

value = typedArray.getString(R.styleable.MoneyView_mv_value);
enableChangeColor = typedArray.getBoolean(R.styleable.MoneyView_mv_enableChangeColor, Boolean.TRUE);

typedArray.recycle();

init();
}

private void init() {
inflate(getContext(), R.layout.view_money, this);

textMoneyCurrency = (TextView) findViewById(R.id.text_money_currency);
textMoneyCurrency.setTextSize(TypedValue.COMPLEX_UNIT_PX, currencySize);

textMoneyValue = (TextView) findViewById(R.id.text_money_value);
textMoneyValue.setTextSize(TypedValue.COMPLEX_UNIT_PX, valueSize);

setCurrency(R.string.default_currency);

textMoneyCurrency.setTextColor(defaultColor);
textMoneyValue.setTextColor(defaultColor);

if (TextUtils.isEmpty(value)) {
setValue(R.string.default_value);
} else {
setValue(value);
}
}

public void setCurrency(@StringRes int text) {
textMoneyCurrency.setText(text);
}

public void setCurrency(String text) {
textMoneyCurrency.setText(text);
}

public void setValue(@StringRes int value) {
setValue(getResources().getString(value));
}

public void setValue(String value) {
textMoneyValue.setText(FormatadorValor.VALOR.formata(value));

if (enableChangeColor) {
final int color;
if (getValue().compareTo(BigDecimal.ZERO) < 0) {
color = negativeColor;
} else {
color = defaultColor;
}

textMoneyCurrency.setTextColor(color);
textMoneyValue.setTextColor(color);
}
}

public BigDecimal getValue() {
return new BigDecimal(FormatadorValor.VALOR.desformata(textMoneyValue.getText().toString()));
}

}
[/code]

Para utilizar os atributos customizados no arquivo de layout (xml) é necessário declarar um namespace que será utilizado para referenciar os atributos, como: xmlns:app=”https://schemas.android.com/apk/res-auto”.

@activity_main.xml

[code language=”xml”]
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android" xmlns:app="https://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:orientation="vertical">

<com.tpinho.customviews.ui.custom.MoneyView android:id="@+id/money_main_price" android:layout_width="wrap_content" android:layout_height="wrap_content" app:mv_value="50000"/>

</LinearLayout>
[/code]

MoneyView

MoneyView

No exemplo acima foi definido apenas um atributo customizado: o valor, por meio do atributo mv_value. Assim, os outros atributos da view continuarão com seus valores predefinidos.

Também é possível utilizar todos os atributos correspondentes à view. Como podemos observar abaixo, serão definidos cor padrão, valor, tamanho do texto e cor do texto quando o valor é negativo.

[code language=”xml”]
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android" xmlns:app="https://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:orientation="vertical">

<com.tpinho.customviews.ui.custom.MoneyView android:id="@+id/money_main_price" android:layout_width="wrap_content" android:layout_height="wrap_content" app:mv_defaultColor="#3C3C3C" app:mv_value="-15000" app:mv_valueSize="30sp" app:mv_currencySize="18sp" app:mv_negativeColor="#FFCF0F"/>

</LinearLayout>
[/code]

MoneyView - Valor negativo com cor e tamanho customizado

MoneyView – Valor negativo com cor e tamanho customizado

E é isso! O projeto de exemplo pode ser encontrado neste repositório do Github. Ficou alguma dúvida ou tem alguma sugestão? Aproveite os campos abaixo!