Para demonstrar a criação do ListAdapter customizado foi criado um projeto para exibir em um ListView os estados do Brasil, juntamente com a abreviação, nome da capital, área em km2 e a imagem da bandeira do estado. O projeto rodando apresenta a seguinte tela:
O projeto possui somente uma Activity que carrega o ListView no método OnCreate() demonstrado no arquivo Main.java.
public class Main extends ListActivity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
List<State> stateList = new ArrayList<State>();
for (int i = 0; i < states.length; i++) {
State state = new State();
state.setState(states[i][0]);
state.setAbbreviation(states[i][1]);
state.setCapital(states[i][2]);
state.setArea(Float.parseFloat(states[i][3]));
state.setBanner(images[i]);
stateList.add(state);
}
setListAdapter(new StateAdapter(this, stateList));
}
private String[][] states = new String[][]{
{"Acre", "AC", "Rio Branco", "152581.4"},
{"Alagoas", "AL", "Maceió", "27767.7"},
{"Amapá", "AP", "Macapá", "142814.6"},
{"Amazonas", "AM", "Manaus", "1570745.7"},
{"Bahia", "BA", "Salvador", "564692.7"},
{"Ceará", "CE", "Fortaleza", "148825.6"},
{"Distrito Federal", "DF", "Brasília", "5822.1"},
{"Espírito Santo", "ES", "Vitória", "46077.5"},
{"Goiás", "GO", "Goiânia", "340086.7"},
{"Maranhão", "MA", "São Luís", "331983.3"},
{"Mato Grosso", "MT", "Cuiabá", "903357.9"},
{"Mato Grosso do Sul", "MS", "Campo Grande", "357125.0"},
{"Minas Gerais", "MG", "Belo Horizonte", "586528.3"},
{"Pará", "PA", "Belém", "1247689.5"},
{"Paraíba", "PB", "João Pessoa", "56439.8"},
{"Paraná", "PR", "Curitiba", "199314.9"},
{"Pernambuco", "PE", "Recife", "98311.6"},
{"Piauí", "PI", "Teresina", "251529.2"},
{"Rio de Janeiro", "RJ", "Rio de Janeiro", "43696.1"},
{"Rio Grande do Norte", "RN", "Natal", "52796.8"},
{"Rio Grande do Sul", "RS", "Porto Alegre", "281748.5"},
{"Rondônia", "RO", "Porto Velho", "237576.2"},
{"Roraima", "RR", "Boa Vista", "224299.0"},
{"Santa Catarina", "SC", "Florianópolis", "95346.2"},
{"São Paulo", "SP", "São Paulo", "248209.4"},
{"Sergipe", "SE", "Aracaju", "21910.3"},
{"Tocantins", "TO", "Palmas", "277620.9"}
};
private int[] images = new int[]{
R.drawable.acre,
R.drawable.alagoas,
R.drawable.amapa,
R.drawable.amazonas,
R.drawable.bahia,
R.drawable.ceara,
R.drawable.distritofederal,
R.drawable.espiritosanto,
R.drawable.goias,
R.drawable.maranhao,
R.drawable.matogrosso,
R.drawable.matogrossosul,
R.drawable.minasgerais,
R.drawable.para,
R.drawable.paraiba,
R.drawable.parana,
R.drawable.pernambuco,
R.drawable.piaui,
R.drawable.riojaneiro,
R.drawable.riograndenorte,
R.drawable.riograndesul,
R.drawable.rondonia,
R.drawable.roraima,
R.drawable.santacatarina,
R.drawable.saopaulo,
R.drawable.sergipe,
R.drawable.tocatins
};
}
No método OnCreate() foi criado um ArrayList com as informações dos estados. Normalmente este tipo de informação é carregada de uma base de dados ou de alguma outra fonte de informação, mas como o objetivo é demonstrar a utilização do ListView, foi criado um array com as informações dos estados (states) e outro array com as imagens das bandeiras (images). As imagens foram obtidas dos arquivos colocados na pasta de resource res/drawable-mdpi.
Para montar o ArrayList foi utilizada a classe State, descrita no arquivo State.java:
public class State {
private String state;
private String abbreviation;
private String capital;
private float area;
private int banner;
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public String getAbbreviation() {
return abbreviation;
}
public void setAbbreviation(String shortening) {
this.abbreviation = shortening;
}
public String getCapital() {
return capital;
}
public void setCapital(String capital) {
this.capital = capital;
}
public float getArea() {
return area;
}
public void setArea(float area) {
this.area = area;
}
public int getBanner() {
return banner;
}
public void setBanner(int banner) {
this.banner = banner;
}
}
O cursor para as informações do ListView é montado utilizando o método setListAdapter(ListAdapter adapter) da classe ListActivity. No parâmetro adapter foi utilizada a classe StateAdapter que recebe como parâmetros o contexto da Activity e o ArrayList com as informações dos estados. O arquivo StateAdapter.java descreve os métodos que são necessários para montar o cursor do ListView.
/**
* Adapter utilizado para exibir as informações dos Estados
* no ListView.
* @author Administrador
*
*/
public class StateAdapter extends BaseAdapter {
private Context context;
private List<State> stateList;
public StateAdapter(Context context, List<State> statelist){
this.context = context;
this.stateList = statelist;
}
@Override
public int getCount() {
return stateList.size();
}
@Override
public Object getItem(int position) {
return stateList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// Recupera o estado da posição atual
State state = stateList.get(position);
// Cria uma instância do layout XML para os objetos correspondentes
// na View
LayoutInflater inflater = (LayoutInflater)
context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.listview_states, null);
// Estado - Abreviação
TextView textState = (TextView)view.findViewById(R.id.textState);
textState.setText(state.getState() + " - " + state.getAbbreviation());
// Capital
TextView textCapital = (TextView)view.findViewById(R.id.textCapital);
textCapital.setText(state.getCapital());
// Área
TextView textArea = (TextView)view.findViewById(R.id.textArea);
textArea.setText(String.valueOf(state.getArea()));
// Bandeira
ImageView img = (ImageView)view.findViewById(R.id.imageState);
img.setImageResource(state.getBanner());
return view;
}
}
A classe StateAdapter extende a classe BaseAdapter que deve implementar os métodos:
- getCount(): retorna o número de itens.
- getItem(int position): retorna o item de uma posição específica.
- getItemId(int position): retorna o Id de um item de uma posição específica.
- getView(int position, View convertView, ViewGroup parent): retorna a View com as informações posicionadas de acordo com o layout montado no arquivo listview_states.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="5dp"
android:background="#cccccc"
>
<ImageView
android:id="@+id/imageState"
android:layout_width="60dp"
android:layout_height="42dp"
android:background="#ffffff"
android:scaleType="centerCrop"
/>
<TextView
android:id="@+id/textState"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_toRightOf="@+id/imageState"
android:layout_alignTop="@+id/imageState"
android:text="São Paulo - SP"
android:textSize="20sp"
android:textColor="#333333"
android:paddingLeft="5dp"
/>
<TextView
android:id="@+id/textCapital"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/textState"
android:layout_toRightOf="@+id/imageState"
android:text="São Paulo"
android:textColor="#333333"
android:paddingLeft="5dp"
/>
<TextView
android:id="@+id/textArea"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/textState"
android:layout_alignParentRight="true"
android:text="100000"
android:textColor="#333333"
/>
</RelativeLayout>
No método getView utilizando a classe LayoutInflater e a classe View podemos associar cada widget do layout à informação que deve ser exibida no ListView.
No exemplo deste post, quando um item do ListView recebe o foco a tradicional cor “Laranja” de fundo não aparece. Isto acontece porque o ListView possui uma cor de fundo opaca, neste caso “cinza”. Na verdade o foco “Laranja” é exibido, mas somente atrás do background do ListView.
Uma possível solução para exibir o fundo “Laranja” neste caso, é fazer uma pequena alteração da definição do layout da tela.
Primeiro precisamos criar um arquivo tipo StateList para definir as cores que serão apresentadas quando o item do ListView for pressionado, selecionado ou receber foco. Para isso foi criado o arquivo list_selector.xml, que deve ser colocado no diretório res/drawable
<?xml version="1.0" encoding="utf-8"?>
<selector
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:state_pressed="true"
android:drawable="@android:color/transparent" />
<item
android:state_selected="true"
android:drawable="@android:color/transparent" />
<item
android:state_focused="true"
android:drawable="@android:color/transparent" />
<item
android:drawable="@color/cinza" />
</selector>
Os itens relativos aos estados pressionado, selecionado ou com focus devem ser configurados com o atributo android:drawable com cor transparente, somente o último item que representa o item sem mudança de estado deve ser configurado com a cor cinza. A cor cinza foi declarada no arquivo color.xml que deve ser colocado no diretório res/values.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="cinza">#cccccc</color>
</resources>
Para que o fundo “laranja” funcione altere no arquivo listview_states.xml o atributo android:drawable da tag RelativeLayout de android:background="#cccccc" para android:background="@drawable/list_selector".
Agora quando um item for clicado teremos a seguinte tela: