Trocando máscara de um EditText no Android em tempo de execução

Mascara - CNPJ

Uma das dificuldades encontradas com relação a máscara, é a troca de um campo do tipo EditText em tempo de execução.
Para isso, criei um projeto Android no Eclipse e criei a seguinte classe, a qual é responsável por altear a máscara para o tipo desejado.

package br.com.rezende.mascaras;

import android.text.Editable;
import android.text.TextWatcher;
import android.widget.EditText;

public abstract class Mask {
    public static String unmask(String s) {
        return s.replaceAll("[.]", "").replaceAll("[-]", "")
                .replaceAll("[/]", "").replaceAll("[(]", "")
                .replaceAll("[)]", "");
    }

    public static TextWatcher insert(final String mask, final EditText ediTxt) {
        return new TextWatcher() {
            boolean isUpdating;
            String old = "";

            public void onTextChanged(CharSequence s, int start, int before,
                    int count) {
                String str = Mask.unmask(s.toString());
                String mascara = "";
                if (isUpdating) {
                    old = str;
                    isUpdating = false;
                    return;
                }
                int i = 0;
                for (char m : mask.toCharArray()) {
                    if (m != '#' && str.length() > old.length()) {
                        mascara += m;
                        continue;
                    }
                    try {
                        mascara += str.charAt(i);
                    } catch (Exception e) {
                        break;
                    }
                    i++;
                }
                isUpdating = true;
                ediTxt.setText(mascara);
                ediTxt.setSelection(mascara.length());
            }

            public void beforeTextChanged(CharSequence s, int start, int count,
                    int after) {
            }

            public void afterTextChanged(Editable s) {
            }
        };
    }
}

O método insert() é responsável por criar um objeto do tipo TextWatcher que contém a máscara desejada, armazene esse objeto em sua Activity para uso posterior, conforme código abaixo:

package br.com.rezende.mascaras;

import android.app.Activity;
import android.os.Bundle;
import android.text.TextWatcher;
import android.widget.EditText;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.RadioGroup.OnCheckedChangeListener;

public class MainActivity extends Activity {
    private TextWatcher cpfMask;
    private TextWatcher cnpjMask;
    private RadioGroup radioGroup;
    private RadioButton rdCNPJ;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        final EditText cpf = (EditText) findViewById(R.id.txtCPF);
        // Armazene seus TextWatcher para posterior uso
        cpfMask = Mask.insert("###.###.###-##", cpf);
        cpf.addTextChangedListener(cpfMask);

        cnpjMask = Mask.insert("##.###.###/####-##", cpf);
        rdCNPJ = (RadioButton) findViewById(R.id.rdCNPJ);

        radioGroup = (RadioGroup) findViewById(R.id.radioGroup);
        radioGroup.setOnCheckedChangeListener(new OnCheckedChangeListener() {

            @Override
            public void onCheckedChanged(RadioGroup group, int checkedId) {
                int opcao = radioGroup.getCheckedRadioButtonId();
                if (opcao == rdCNPJ.getId()) {
                    cpf.removeTextChangedListener(cpfMask);
                    cpf.addTextChangedListener(cnpjMask);
                } else {
                    cpf.removeTextChangedListener(cnpjMask);
                    cpf.addTextChangedListener(cpfMask);
                }
            }
        });

    }
}

Observe que nas linhas 36 e 39 é realizado um removeTextChangedListener antes do mesmo adicionar a nova máscara ao campo.

Assim, toda vez que um tipo de documento (CPF ou CNPJ) for escolhido em sua Activity, a máscara de edição é alterada.
Se preferir criar sua xml de tela, segue código.

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" >

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:orientation="vertical" >

        <EditText
            android:id="@+id/txtCPF"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:inputType="text" >

            <requestFocus />
        </EditText>

        <RadioGroup
            android:id="@+id/radioGroup"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" >

            <RadioButton
                android:id="@+id/rdCPF"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:checked="true"
                android:text="CPF" />

            <RadioButton
                android:id="@+id/rdCNPJ"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:text="CNPJ" />
        </RadioGroup>
    </LinearLayout>

</RelativeLayout>

Essa tela deverá ficar com o seguinte layout:

CPF

 

Abraços,
André Rezende

Anúncios

8 comentários sobre “Trocando máscara de um EditText no Android em tempo de execução

  1. Parabéns pelo Post.
    Encontrei algo semelhante na internet, no entanto, ninguém explica como retirar a máscara do campo. Espero poder conseguir da forma explicada acima.

    Abraço.

  2. Há um problema aí que é na hora de apagar a máscara vai embora, ficando bem feio.. em casos de telefone, por ex, se você digitou um número a mais e remove e o número final está correto, vai ficar sem a formatação adequada!
    Resolvi essa questão alterando o código acima para este:

    int i = 0;
    if( str.length() > old.length()){
    for (char m : mask.toCharArray()) {
    if (m != ‘#’) {
    mascara += m;
    continue;
    }else{
    try {
    mascara += str.charAt(i);
    } catch (Exception e) {
    break;
    }
    i++;
    }
    }
    }else{
    mascara = s.toString();
    }

  3. import android.text.Editable;
    import android.text.TextWatcher;
    import android.widget.EditText;

    public abstract class Mask {
    public static String CPF_MASK = “###.###.###-##”;
    public static String CELULAR_MASK = “(##) #### #####”;
    public static String CEP_MASK = “#####-###”;

    public static String unmask(String s) {
    return s.replaceAll(“[.]”, “”).replaceAll(“[-]”, “”)
    .replaceAll(“[/]”, “”).replaceAll(“[(]”, “”)
    .replaceAll(“[)]”, “”).replaceAll(” “, “”)
    .replaceAll(“,”, “”);
    }

    public static boolean isASign(char c) {
    if (c == ‘.’ || c == ‘-‘ || c == ‘/’ || c == ‘(‘ || c == ‘)’ || c == ‘,’ || c == ‘ ‘) {
    return true;
    } else {
    return false;
    }
    }

    public static String mask(String mask, String text) {
    int i = 0;
    String mascara = “”;
    for (char m : mask.toCharArray()) {
    if (m != ‘#’) {
    mascara += m;
    continue;
    }
    try {
    mascara += text.charAt(i);
    } catch (Exception e) {
    break;
    }
    i++;
    }

    return mascara;
    }

    public static TextWatcher insert(final String mask, final EditText ediTxt) {
    return new TextWatcher() {
    boolean isUpdating;
    String old = “”;

    public void onTextChanged(CharSequence s, int start, int before, int count) {
    String str = Mask.unmask(s.toString());
    String mascara = “”;
    if (isUpdating) {
    old = str;
    isUpdating = false;
    return;
    }

    int index = 0;
    for (int i = 0; i < mask.length(); i++) {
    char m = mask.charAt(i);
    if (m != '#') {
    if (index == str.length() && str.length() 0) {
    char last_char = mascara.charAt(mascara.length() – 1);
    boolean hadSign = false;
    while (isASign(last_char) && str.length() == old.length()) {
    mascara = mascara.substring(0, mascara.length() – 1);
    last_char = mascara.charAt(mascara.length() – 1);
    hadSign = true;
    }

    if (mascara.length() > 0 && hadSign) {
    mascara = mascara.substring(0, mascara.length() – 1);
    }
    }

    isUpdating = true;
    ediTxt.setText(mascara);
    ediTxt.setSelection(mascara.length());
    }

    public void beforeTextChanged(CharSequence s, int start, int count, int after) {}

    public void afterTextChanged(Editable s) {}
    };
    }
    }

    Ae ta o codigo da classe Mask. Com a diferença que ele vai funcionar tbm enquanto estiver deletando os characters. Levei quase 2 dias para implementar essa função adequadamente. Ta bem testada jah.

    Use essa classe assim:

    EditedText etCPF = /* sua inicialização aqui */;
    etCPF.addTextChangedListener(Mask.insert(Mask.CPF_MASK, etCPF));

  4. Gostei Muito , resolveu meu problema

  5. André, boa tarde.

    Primeiramente, parabéns pelo trabalho. Ficou excelente e me é muito útil. Em segundo lugar, detectei um pequeno problema e fiz uma alteração. Quando o usuário deleta um char, o cursor vai automaticamente para o fim. Reparei em testes de producao que muitas vezes as pessoas nem percebem que o cursor foi para o fim, e, quando desejam apagar mais de um numero, acabam errando e nao percebem. Além disso, inclui espaços como char possível para a máscara também. Compartilho aqui abaixo o código, mas gostaria de sugerir que voce o colocasse no github, para que todos possam contribuit, (como muitos estao fazendo nos comentarios acima). Além disso, seria bem legal para o seu currículo também. Abraços!

    public abstract class Mask {

    public static String unmask(String s) {
    return s.replaceAll(“[.]”, “”).replaceAll(“[-]”, “”)
    .replaceAll(“[/]”, “”).replaceAll(“[(]”, “”)
    .replaceAll(“[)]”, “”).replaceAll(” “, “”);
    }

    public static TextWatcher insert(final String mask, final EditText ediTxt) {
    return new TextWatcher() {
    boolean isUpdating = false;
    int selection = 0;
    int beforeTextSize;
    String old = “”;

    public void onTextChanged(CharSequence s, int start, int before,
    int count) {
    String str = Mask.unmask(s.toString());
    String mascara = “”;
    if (isUpdating) {
    old = str;
    isUpdating = false;
    return;
    }
    int i = 0;
    for (char m : mask.toCharArray()) {
    if (m != ‘#’ && str.length() > old.length()) {
    mascara += m;
    continue;
    }
    try {
    mascara += str.charAt(i);
    } catch (Exception e) {
    break;
    }
    i++;
    }
    isUpdating = true;
    if (str.length() >= old.length()) {
    ediTxt.setText(mascara);
    // selection += selection < mask.length() &&
    // mask.charAt(selection) != '#' ? count + 1 : count;
    selection += selection + 1 < mask.length() &&
    (mask.charAt(selection) != '#' || mask.charAt(selection+1) != '#') ? count + 1 : count;
    ediTxt.setSelection(selection <= mascara.length() ? selection : mascara.length());
    }
    }

    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
    if (!isUpdating) {
    selection = ediTxt.getSelectionStart();
    Log.d(TAG, "beforeTextChanged: " + selection);
    }
    }

    public void afterTextChanged(Editable s) {
    }
    };
    }

    }

  6. Boa sugestão, devo logo colocar no github já com as correções.

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s