Formatar campos de CEP e Telefone

659 views
Skip to first unread message

Júlio Cesar Bueno Cotta

unread,
Sep 3, 2011, 11:08:23 AM9/3/11
to androidbrasil-dev
Olha eu ai de novo precisando de ajuda.
Pessoal, estive dando uma olhada na internet e achei um "formatador" de números de telefone padrão do Android para EditText, mas acho que ele não serviria para mim por possuir muitos campos.
Tem como formatar o texto digitado em um EditText nos formatos abaixo?
CEP:
09210-660
e Tel:
(11)1234-4321

O tal "formatador":
EditText inputField = (EditText) findViewById(R.id.inputfield);
inputField
.addTextChangedListener(new PhoneNumberFormattingTextWatcher());
Teria como eu passar uma expressão regular para ele, ou algo assim?
Abraço

--
Júlio Cesar Bueno Cotta
Bacharel em Ciência da Computação pela UFV
Mestrando em Ciência da Computação pela UFABC

Bruno Albuquerque

unread,
Sep 4, 2011, 8:31:46 AM9/4/11
to androidb...@googlegroups.com
O PhoneNumberFormattingTextWatcher é im TextWatcher
(http://developer.android.com/reference/android/text/TextWatcher.html).
Tudo que você precisa fazer é criar sua própria classe que estende
essa e que faz o que você precisa.

-Bruno

2011/9/3 Júlio Cesar Bueno Cotta <julioc...@gmail.com>:

Júlio Cesar Bueno Cotta

unread,
Sep 4, 2011, 11:20:46 AM9/4/11
to androidb...@googlegroups.com
Bruno, muito obrigado pela resposta, estou tentando fazer algo assim:
        etClientCEP.addTextChangedListener(new TextWatcher() {
            DecimalFormat df = new DecimalFormat("#####.###");
           
            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
            }

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

            @Override
            public void afterTextChanged(Editable s) {
                String cep = s.toString().replace("-", "");
                if (cep.length() == 5) {
                    cep = cep +"-";
                   
                }else if(cep.length() >= 6){
                    String parte1 = cep.substring(0, 5);
                    String parte2 = cep.substring(5);
                    cep = parte1 +"-" + parte2;
                }
                Log.w("CEP", cep);
                //etClientCEP.setText(cep);
            }
        });

Mas ao digitar dá um erro que parece ser de recursão recursão, pois dá stack overflow quando a linha
                //etClientCEP.setText(cep); está descomentada...o que até que faz sentido..mas como evitar isso?

Desde já, muito obrigado pela ajuda.

Bruno Albuquerque

unread,
Sep 4, 2011, 4:15:43 PM9/4/11
to androidb...@googlegroups.com
Antes de mais nada, melhor fazer esse metodo ser synchronized.

Evitar o loop é simples. Use um atributo de clase pra indicar se você
está editando ou não (um boolean cabe perfeitamente aqui). Ai, no seu
método, cheque essa variavel e tome as as ações adequadas. Algo como:

private boolean processingText;

[...]

public void afterTextChanged(Editable s) {
if (!processingText) {
processingText = true;

[Altere o editable como quiser]

processingText = false;
}
}

-Bruno

2011/9/4 Júlio Cesar Bueno Cotta <julioc...@gmail.com>:

Júlio Cesar Bueno Cotta

unread,
Sep 4, 2011, 5:05:24 PM9/4/11
to androidb...@googlegroups.com
Nossa, uma solução simples e que funciona!
Muito obrigado!
Agora tem outro problema ainda nesse campo...
quando começo a digitar está ficando assim..onde o pipe ("|") é o cursor
|__________
|0_________
|90________
|290_______
|1290______
|01290_____
sendo que o cep que estou digitando é 09210...
Como fazer para que o cursor da tela fique a direita do último número digitado? Acho que isso resolveria meu problema..mas não faço ideia de como manipular isso.

Obrigado!

Júlio Cesar Bueno Cotta

unread,
Sep 4, 2011, 5:50:14 PM9/4/11
to androidb...@googlegroups.com
Uhu \o/
Consegui fazer! O truque está na parte em negrito e na variável tamVelho.
Muito obrigado Bruno!!!
Agora vou ver a parte de formatar o telefone. :-D

        etClientCEP.addTextChangedListener(new TextWatcher() {
            private boolean editando =  false;
            private String cep;
            private int tamVelho = 0;

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
            }

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

            }

            @Override
            public void afterTextChanged(Editable s) {
                if (!editando) {
                    cep = etClientCEP.getText().toString().replace("-", "").toString();
                    editando = !editando;   
                    if (cep.length() == 5 && 5 > tamVelho) {

                        cep = cep + "-";
                    } else if (cep.length() >= 6) {

                        String parte1 = cep.substring(0, 5);
                        String parte2 = cep.substring(5);
                        cep = parte1 + "-" + parte2;
                    }
                    Log.w("CEP", cep);
                    tamVelho = cep.length();
                    if(cep.length() > 0){
                        etClientCEP.setTextKeepState(cep, BufferType.EDITABLE);
                        etClientCEP.setSelection(cep.length());
                    }
                   
                    editando = !editando;
                }
            }
        });

Júlio Cesar Bueno Cotta

unread,
Sep 4, 2011, 11:02:42 PM9/4/11
to androidb...@googlegroups.com
\o/²
Finalmente, depois de horas e mais horas de debug..formatação de telefone OK.
Espero que ajude alguém..

    private void setPhoneTextWatcher(final EditText et) {
        et.addTextChangedListener(new TextWatcher() {

            private boolean editando = false;
            private String fone;

            private int tamVelho = 0;

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                if (!editando) {
                    editando = !editando;
                    String text = et.getText().toString();
                    fone = text.replaceAll("\\(", "").replaceAll("\\)", "").replaceAll("-", "")
                            .replaceAll(" ", "");

                    if (fone.length() >= 2 && fone.length() > tamVelho) {
                        String parte0 = fone.substring(0, 2);
                        String parte1 = fone.substring(2);
                        String parte2 = "";
                       
                        if (fone.length() < 6) {
                            tamVelho = fone.length();
                            fone = "(" + parte0 + ") " + parte1;
                        } else {
                            parte1 = fone.substring(2, 6);
                            parte2 = fone.substring(6);
                            tamVelho = fone.length();
                            fone = "(" + parte0 + ") " + parte1 + "-" + parte2;
                        }

                    } else {
                        tamVelho = fone.length();
                        fone = text;
                    }


                    if (fone.length() > 2) {
                        et.setTextKeepState(fone, BufferType.EDITABLE);
                        et.setSelection(fone.length());
                    }
                    editando = !editando;

                }

            }

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

            @Override
            public void afterTextChanged(Editable s) {

            }

Bruno Albuquerque

unread,
Sep 5, 2011, 2:19:09 PM9/5/11
to androidb...@googlegroups.com
Cara, existe alguns problemas com seu código. O maior deles é que você
deve reservar override de classe inline apenas para coisas bem
simples, o que não é o caso desse código. Mova isso pra uma classe
propriamnente dita. :)

-Bruno

2011/9/5 Júlio Cesar Bueno Cotta <julioc...@gmail.com>:

Júlio Cesar Bueno Cotta

unread,
Sep 5, 2011, 4:04:53 PM9/5/11
to androidb...@googlegroups.com
Putz.."Muitos problemas?" Pode falar mais?

Bem, ali eu deixei "para funcionar", sei que criar uma classe sem nome não é uma boa pratica, o código fica feio e perde-se a reusabilidade...
Na verdade eu acabei criando os meus TextWatcher -> CEPWatcher e TelefoneWatcher em uma classe "Util" para funcionar como uma biblioteca para o projeto...
Hehe, na falta de alguém que me diga como fazer, fiz de modo que funcione para mim, mas aceito sugestões. :-D
Obrigado pelas dicas Bruno.

Bruno Albuquerque

unread,
Sep 5, 2011, 4:27:58 PM9/5/11
to androidb...@googlegroups.com
"Alguns", não "muitos". Vamos lá.

O método onTextChanged precisa ser synchronized (como eu já havia mencionado).

A legibilidade de "editando = !editando" é quase 0. Mude para
"editando = true" e "editando = false".

Por que exatamente você espera que no número de telefone entrado pelo
usuário exista uma barra invertida ("\")?

Você pode mudar as 4 chamadas encadeadas do replaceAll() em uma única.
Mova a string com o regex para uma constante.

Use parentesis em cada subexpressão nos blocos if. Fica mais legível.
Por exemplo, mude:

if (fone.length() >= 2 && fone.length() > tamVelho)

para:

if ((fone.length() >= 2) && (fone.length() > tamVelho))

Isso deve te dar uma idéia.

Alexandre Silveira

unread,
Sep 5, 2011, 4:56:50 PM9/5/11
to androidb...@googlegroups.com
Outra dica é mudar os números mágicos por constantes 

5 para "TAMANHO_PRIMEIRA_PARTE_CEP", por exemplo

;)

2011/9/5 Bruno Albuquerque <bruno.al...@gmail.com>



--
_________________________________
Alexandre Silveira Neto
Analista e Desenvolvedor de Sistemas
Voiza - Soluções em Java

Júlio Cesar Bueno Cotta

unread,
Sep 5, 2011, 5:00:10 PM9/5/11
to androidb...@googlegroups.com
ahhh,,vou respondendo no corpo da sua resposta. :-D

Em 5 de setembro de 2011 17:27, Bruno Albuquerque <bruno.al...@gmail.com> escreveu:
"Alguns", não "muitos". Vamos lá.

Ok.
O método onTextChanged precisa ser synchronized (como eu já havia mencionado).

A legibilidade de "editando = !editando" é quase 0. Mude para
"editando = true" e "editando = false".

Anotado. E eu achando que estava abalando fazendo isso.. :-P
 
Por que exatamente você espera que no número de telefone entrado pelo
usuário exista uma barra invertida ("\")?

Bem, não espero que ele digite contra barra, mas se eu deixar somente "(" ou ")" dá ( deu) erro de expressão na hora de executar, acredito que parenteses sejam usados como caractere especial para regexp no Java, para evitar a interpretação coloquei o contra barra...
algo como isso:
09-05 17:58:15.791: ERROR/AndroidRuntime(1004): Caused by: java.util.regex.PatternSyntaxException: Syntax error U_REGEX_MISMATCHED_PAREN near index 1:
09-05 17:58:15.791: ERROR/AndroidRuntime(1004): (
09-05 17:58:15.791: ERROR/AndroidRuntime(1004):  ^
09-05 17:58:15.791: ERROR/AndroidRuntime(1004):     at com.ibm.icu4jni.regex.NativeRegEx.open(Native Method)
09-05 17:58:15.791: ERROR/AndroidRuntime(1004):     at java.util.regex.Pattern.compileImpl(Pattern.java:264)
09-05 17:58:15.791: ERROR/AndroidRuntime(1004):     at java.util.regex.Pattern.<init>(Pattern.java:239)
09-05 17:58:15.791: ERROR/AndroidRuntime(1004):     at java.util.regex.Pattern.compile(Pattern.java:179)
09-05 17:58:15.791: ERROR/AndroidRuntime(1004):     at java.lang.String.replaceAll(String.java:2085)

Você pode mudar as 4 chamadas encadeadas do replaceAll() em uma única.
Mova a string com o regex para uma constante.

Sim, mas...montar regexp? Que preguiça de estudar isso..me faz lembrar as aulas de compiladores...e acho que é mais fácil de ler o replaceAll do que uma regexp. :-P
 Mas, vou pensar no caso.. será que rola uma ajudinha nisso?

Use parentesis em cada subexpressão nos blocos if. Fica mais legível.
Por exemplo, mude:

if (fone.length() >= 2 && fone.length() > tamVelho)

para:

if ((fone.length() >= 2) && (fone.length() > tamVelho))

hehe, eu costumo fazer isso, mas as vezes eu esqueço.
 

Júlio Cesar Bueno Cotta

unread,
Sep 5, 2011, 5:02:25 PM9/5/11
to androidb...@googlegroups.com
Hehe, vou fazer isso Alexandre. :-D
Obrigado!

Bruno Albuquerque

unread,
Sep 5, 2011, 5:19:04 PM9/5/11
to androidb...@googlegroups.com
Pelo menos no código que você postou, você usou "\\(" (note duas
barras). Provavelmente o que você queria era "\(" (uma barra. Isso
indica que o caracter seguindo a mesma deve ser interpretado
literalmente). Mas, caso esteja funcionando, é possível que o
double-scaping seja necessário (não sou especialista nas
particularidades de regex do java).

Thiago Lopes Rosa

unread,
Sep 6, 2011, 10:15:40 AM9/6/11
to androidb...@googlegroups.com
Julio,
Use esse site pra fazer as regexs:

(é legal pois dá pra ir fazendo e vendo o resultado ao mesmo tempo)




Thiago

Júlio Cesar Bueno Cotta

unread,
Sep 6, 2011, 11:02:28 AM9/6/11
to androidb...@googlegroups.com
Haha, que legal, o site aceita o pipe "|" como "ou" ...mas não consegui passar para o Java de modo que funcione..
No site..(-|\(|\)| ) funciona para (XX) XXXX-XXXX
o correspondente quando colocado no replaceAll não funciona legal.. :-(
Depois eu testo melhor..
Obrigado pelo site Thiago!

Italo Naia

unread,
Sep 6, 2011, 11:11:22 AM9/6/11
to androidb...@googlegroups.com
o regexpal é regex para Javascript (se não me engano e POSIX a sintaxe)...... não sei se em Java usa o mesmo padrão.....

nem sempre é....... por isso não deve funcionar o PIPE.....

eu tinha um link q tinha regex pra varias linguagens parecido com esse regexpal..... mas não encontrei aqui.....

se achar te mando...

2011/9/6 Júlio Cesar Bueno Cotta <julioc...@gmail.com>
Reply all
Reply to author
Forward
0 new messages