Como Customizar a Cor de Fundo de um Botão no Android

Neste post vou demonstrar como configurar a cor de fundo de um botão utilizando duas técnicas diferentes. Uma utilizando figuras com cor em degradê, para dar o efeito do botão sendo pressionado, e outra utilizando o mesmo efeito degradê só que, fazendo a configuração do botão utilizando um arquivo xml.

Para este exemplo criei um projeto com dois botões com cor em degradê como demonstrado na Figura 1.

background1
Figura 1
Para montar o layout dois dois botões foi utilizado o seguinte código no arquivo main.xml (Listagem 1):

Listagem 1:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
 
    <!-- View utilizada como separador -->
    <View
        android:layout_width="fill_parent" 
        android:layout_height="10sp"        
        android:id="@+id/view1"
     />
 
    <Button 
        android:id="@+id/btnJpg"
        android:layout_width="200dp"
        android:layout_height="50dp"
        android:layout_centerHorizontal="true"
        android:layout_below="@+id/view1"
        android:text="Design por Figura Jpg"
        android:background="@drawable/botao_azul_selector"
    />
    
        <!-- View utilizada como separador -->
    <View
        android:layout_width="fill_parent" 
        android:layout_height="10sp"        
        android:id="@+id/view2"
        android:layout_below="@+id/btnJpg"
     />
    
    <Button 
        android:id="@+id/btnXml"
        android:layout_width="200dp"
        android:layout_height="50dp"
        android:layout_centerHorizontal="true"
        android:layout_below="@+id/view2"
        android:text="Design por Arquivo Xml"
        android:background="@drawable/botao_verde_selector"
    />    
</RelativeLayout>


No primeiro botão btnJpg foi utilizado como cor de fundo duas figuras em degradê uma para quando o botão for pressionado e outra para quando o botão for solto. É necessário utilizar duas figuras para dar o efeito dinâmico do botão estar sendo pressionado.

Para configurar este efeito utilizei um recurso chamado de StateListDrawable que é um arquivo xml onde podemos configurar figuras diferentes para cada estado, por exemplo de um botão.
Este arquivo xml deve ser colocado em um diretório \drawable. O arquivo para configurar o primeiro botão é o botão_azul_selector (Listagem 2), configurado no atributo android:background="@drawable/botao_azul_selector".

Listagem 2:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item
         android:state_pressed="true" 
        android:drawable="@drawable/botao_azul_on"
    />
    <item 
        android:drawable="@drawable/botao_azul_off"
    />
</selector>


No estado android:state_pressed foi utilizada a figura botao_azul_on para representar o botão quando pressionado e a figura botao_azul_off para representar o botão no estado não pressionado. As figuras do botão devem estar em um diretório \drawable.

No segundo botão btnXml foi utilizada uma outra técnica de configurar a cor de fundo do botão. O princípio é o mesmo, foi utilizado um arquivo Xml para configurar a aparência do botão em cada um dos estados (pressionado ou não), só que desta vez ao invés de utilizar figuras .jpg, foram utilizadas tags para construir a forma geométrica do botão. O arquivo botao_verde_selector também deve ser colocado em um diretório \drawable (Listagem 3):

Listagem 3:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true" >
        <shape>
            <gradient
                android:startColor="@color/verde_claro" 
                android:endColor="@color/verde_escuro"
                android:angle="270" />
            <stroke
                android:width="1dp"
                android:color="@color/verde_escuro" />
            <corners
                android:radius="10dp" />
            <padding
                android:left="10dp"
                android:top="10dp"
                android:right="10dp"
                android:bottom="10dp" />
        </shape>
    </item>
    <item>
       <shape>
            <gradient
                android:startColor="@color/verde_escuro" 
                android:endColor="@color/verde_claro"
                android:angle="270" />
            <stroke
                android:width="1dp"
                android:color="@color/verde_escuro" /> 
            <corners
                android:radius="10dp" />
            <padding
                android:left="10dp"
                android:top="10dp"
                android:right="10dp"
                android:bottom="10dp" />
        </shape>
    </item>
</selector>

A aparência do botão verde é construída através da tag de forma <shape> cujo default é o retângulo. Dentro desta tag temos a tag <gradient> que define a cor degradê, a tag <stroke> que define a largura e a cor do contorno do botão, a tag <corners> que define o ângulo da borda arredondada do nosso botão e a tag <padding> que define o posicionamento do conteúdo e não da forma geométrica do botão.

Observe que foram criadas duas tags <item>, uma para o estado pressionado do botão e outra para o estado default do botão.
Para rodar a aplicação foi criada a Activity Principal (Listagem 4):

Listagem 4:
public class Principal extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
}

Como Utilizar o ListView para Selecionar Vários Itens no Android

Neste post vou demonstrar como trabalhar com um ListView que permite a seleção de um ou vários itens, e como tratar o retorno dos itens selecionados.

Criei um projeto onde são exibidas as regiões do Brasil (Figura 1) na Activity principal e quando selecionada uma região é apresentada uma Activity filha (Figura 2) com a relação de estados pertencentes àquela região, com um checkbox que permite a seleção ou não de cada estado (Figura 2).

listviewmultiplechoice4

Quando são selecionados um ou mais estados na Activity filha (Tela com a relação dos estados da região selecionada – Figura 2) e retornamos para a Activity principal (Figura 1) é apresentada uma mensagem com os estados que foram selecionados (Figura 3). No exemplo foi selecionada a região Sudeste na Activity Principal e os estados Minas Gerais, Rio de Janeiro e São Paulo.

listviewmultiplechoice5

No projeto foram criadas duas classes para representar as duas Activities. A primeira classe é a Main.java (Listagem 1)

Listagem 1
public class Main extends ListActivity implements OnItemClickListener {
    private String[] regiao = new String[]{
            "Centro-Oeste", "Nordeste", "Norte",
            "Sudeste", "Sul"};
    private final static int ACTIVITY_STATE = 1;
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
 
        setListAdapter(new ArrayAdapter<String>(this,
                android.R.layout.simple_list_item_1, regiao));
        
        ListView listView = getListView();        
        listView.setOnItemClickListener(this);
    }
 
    @Override
    public void onItemClick(AdapterView<?> parent, View view, 
            int position, long id) {
        String regiao = (String) parent.getItemAtPosition(position);
        
        Intent intent = new Intent(this, StateListActivity.class);
        intent.putExtra("estados", getEstados(regiao));        
        startActivityForResult(intent, ACTIVITY_STATE);
        
    }
    
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        
        // Verifica se o retorno veio da Activity chamada
        if (requestCode == ACTIVITY_STATE) {
            if (resultCode == RESULT_OK) {
                if (data != null) {
                    ArrayList<String> estados = data.getStringArrayListExtra("estados");
                    
                    StringBuilder message = new StringBuilder();
                    message.append("Estados selecionados:\n");
                    
                    for (int i = 0; i < estados.size(); i++) {
                            message.append(estados.get(i) + "\n");
                    }
                    
                    // Exibe o nome dos estados selecionados
                    Toast.makeText(this, message.toString(), Toast.LENGTH_SHORT).show();
                }
            }
        }                
        
    }
    
    private String[] getEstados(String regiao){
        
        if (regiao.equals("Centro-Oeste")) {
            return new String[]{
            "Goiás", "Mato Grosso", "Mato Grosso do Sul",
            "Distrito Federal"};
        }
        
        if (regiao.equals("Nordeste")) {
            return new String[]{
                    "Maranhão", "Piauí", "Ceará", "Rio Grande do Norte",
                    "Paraíba", "Pernambuco", "Alagoas", "Sergipe",
                    "Bahia};
        }
        
        if (regiao.equals("Norte")) {
            return new String[]{
                    "Acre", "Amazonas", "Roraima", "Rondônia",
                    "Pará", "Amapá", "Tocantins"};
        }
        
        if (regiao.equals("Sudeste")) {
            return new String[]{
                    "Minas Gerais", "Espírito Santo", "Rio de Janeiro",
                    "São Paulo"};
        }
        
        if (regiao.equals("Sul")) {
            return new String[]{
                    "Paraná", "Santa Catarina", "Rio Grande do Sul"};
        }
        
        return new String[] { "" };
    }
}

A classe Main.java constroi a tela Principal e trata o retorno dos dados recebidos da Tela dos Estados.

O método onCreate(Bundle) cria um ListView com o layout padrão do Android (android.R.layout.simple_list_item_1) com os dados obtidos da matriz regiao.

O método onItemClick(AdapterView<?>, View, int, long) é chamado quando uma região é selecionada no ListView. Neste método é armazenada a região selecionada na variável local regiao e a Activity dos Estados é exibida através da chamada do método startActivityForResult(intent, int) que exibe a Activity e aguarda o resultado dos estados selecionados quando a Activity chamada retornar para a Activity principal.

O método onActivityResult(int, int, Intent) é chamado quando a Activity de Estados retorna para a Activity Principal. Este método verifica se a Activity que retornou era a Activity esperada através da verificação do parâmetro requestCode, verifica se o resultado está correto através do parâmetro resultCode, obtêm os dados retornados através do parâmetro data e exibe uma mensagem indicando os estados selecionados na Activity de Estados.

O método getEstados(String) retorna uma matriz com os estados de acordo com a região informada no parâmetro regiao.

A segunda classe é a StateListActivity.java (Listagem 2).

Listagem 2
public class StateListActivity extends ListActivity implements OnItemClickListener {
    ListView listView;
    String[] estados;
    ArrayList<String> stateList;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        Intent intent = getIntent();
        
        if (intent != null) {
            estados = intent.getStringArrayExtra("estados");
            
            // Exibe o listview com botão tipo checkbox
            setListAdapter(new ArrayAdapter<String>(this, 
                    android.R.layout.simple_list_item_multiple_choice,
                    estados));
            
            listView = getListView();
            
            // Desabilita o foco no item
            listView.setItemsCanFocus(false);
            
            // Configura o listview para permitir a seleção de
            // vários itens simultaneamente
            listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
            
            listView.setOnItemClickListener(this);
        }
 
    }
 
    @Override
    public void onItemClick(AdapterView<?> parent, View view, 
            int position, long id) {
        stateList = new ArrayList<String>();
        
        // Mapa de Booleans com a informação dos estados selecionados
        SparseBooleanArray status = listView.getCheckedItemPositions();
        
        // Limpa a lista anterior para manter atualizada
        // a última seleção
        stateList.clear();
        
        for (int i = 0; i < status.size(); i++) {
            if (status.valueAt(i) == true) {
                stateList.add((String)listView.getItemAtPosition
                        (status.keyAt(i)));
            }
        }
    }
    
    @Override
    public void onBackPressed() {
        // Verifica se algum estado foi selecionado
        if (stateList != null) {
            // Passa as informações dos estados selecionados para
            // a activity pai
            Intent intent = new Intent();
            intent.putStringArrayListExtra("estados", stateList);
            setResult(RESULT_OK, intent);
        }
        else
        {
            setResult(RESULT_CANCELED);            
        }
 
        super.onBackPressed();
    }
}

A classe StateListActivity.java é responsável por exibir a tela com a relação de estados e permite a seleção ou não de um ou mais estados.

O método onCreate(Bundle) utiliza o método getIntent() para obter a relação de estados que foi passada pela Activity principal (classe Main.java) e exibe a tela com o layout configurado para exibir um listview com botão tipo checkbox, configurado com a opção de selecionar vários itens simultaneamente.

O método onItemClick(AdapterView, View, int, long) é chamado quando um item do listview é selecionado. Neste método é utilizada a classe SparseBooleanArray que faz o mapeamento de boolean para integer e é utilizada para armazenar as informações de quais itens da relação de estados foi selecionado. Com o método valueAt(int) da classe SparseBooleanArray, obtemos o valor se true ou false para cada item, e com o método keyAt(int) obtemos a chave dentro da lista de itens. Esta chave é utilizada para determinar qual o estado que está com o status selecionado.

O método onBackPressed() é chamado quando é acionado o botão “Voltar” do emulador. Este método  passa as informações dos estados selecionados para a Activity principal.

Posts Relacionados: