EditText onClickListener no Android

86

Eu quero um EditText que cria um DatePicker quando é pressionado. Então, escrevo o seguinte código:

    mEditInit = (EditText) findViewById(R.id.date_init);
    mEditInit.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            showDialog(DATEINIT_DIALOG);
        }

    });

Mas quando pressiono EditText, a ação é a típica: um cursor aguardando a digitação do texto mostra a caixa de diálogo que desejo.

xger86x
fonte
Você deve usar um botão giratório em vez de uma caixa de diálogo EditText.
Ryan R

Respostas:

129

O teclado parece abrir quando o EditText ganha foco. Para evitar isso, defina focalizável como falso:

<EditText
    ...
    android:focusable="false"
    ... />

Esse comportamento pode variar nos diferentes tipos de sistema operacional Android dos fabricantes, mas nos dispositivos que testei descobri que isso é suficiente. Se o teclado ainda aparecer, usar dicas em vez de texto também parece ajudar:

myEditText.setText("My text");    // instead of this...
myEditText.setHint("My text");    // try this

Depois de fazer isso, seu ouvinte ao clicar deve funcionar conforme desejado:

myEditText.setOnClickListener(new OnClickListener() {...});
Dillon Kearns
fonte
Isso parece funcionar, mas quando você digita em um campo e clica em Avançar no teclado, ele pula o campo com o foco em falso.
Sterling Diaz
60

Normalmente, você deseja compatibilidade máxima com EditTexto comportamento normal de.

Portanto, você não deve usar android:focusable="false"porque, sim, a visualização simplesmente não será mais focalizável, o que parece ruim. O drawable de fundo não mostrará mais seu estado "pressionado", por exemplo.

O que você deve fazer é o seguinte:

myEditText.setInputType(InputType.TYPE_NULL);
myEditText.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        // showMyDialog();
    }
});
myEditText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
    @Override
    public void onFocusChange(View v, boolean hasFocus) {
        if (hasFocus) {
            // showMyDialog();
        }
    }
});

Ao definir o tipo de entrada para TYPE_NULL, você evita que o teclado do software apareça.

Ao definir o OnClickListenere OnFocusChangeListener, você garante que sua caixa de diálogo sempre será aberta quando o usuário clicar no EditTextcampo, tanto quando ele ganha o foco (primeiro clique) quanto nos cliques subsequentes.

Apenas definir android:inputType="none"ou setInputType(InputType.TYPE_NULL)nem sempre é suficiente. Para alguns dispositivos, você também deve definir android:editable="false"em XML, embora esteja obsoleto. Se não funcionar mais, será simplesmente ignorado (como todos os atributos XML que não são suportados).

crocitar
fonte
Quando eu faço isso, a caixa de diálogo é reaberta após fechar porque o texto de edição ganha o foco novamente. Alguma maneira de contornar isso?
AdamMc331
@ McAdam331 Esse EditTextcomponente é o único widget em seu layout, talvez? Você pode tentar adicionar android:focusable="true"ao seu layout pai?
caw
1
@caw Obrigado por responder, mas acabei fazendo funcionar usando o onTouch. Obrigado!
AdamMc331
É isso aí. Trabalhando bem.
XueQing,
31

Eu tenho esse mesmo problema. O código é bom, mas certifique-se de alterar o valor focalizável do EditText para false.

<EditText
android:id="@+id/date"
android:focusable="false"/>

Espero que isso ajude qualquer pessoa que já teve um problema semelhante!

Yusuf Hoque
fonte
4
Também não defina enabled = "false", o que desativará onClickListener
OatsMantou
25

Funcionamento padrão de EditText: no primeiro clique, ele foca e no segundo clique ele controla, onClickListenerentão você precisa desativar o foco. Então, no primeiro clique, a onClickListeneralça será.

Para fazer isso, você precisa adicionar este android:focusableInTouchMode="false"atributo ao seu EditText. É isso aí!

Algo assim:

    <EditText
        android:id="@+id/editText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:focusableInTouchMode="false"
        android:inputType="text" />
Akshay Chordiya
fonte
4
Funciona, mas EditTexttorna-se não editável e o cursor não aparece.
CoolMind
17

Aqui está a solução que implementei

mPickDate.setOnKeyListener(new View.OnKeyListener() {

    @Override
    public boolean onKey(View v, int keyCode, KeyEvent event) {
        showDialog(DATE_DIALOG_ID);
        return false;
    }
});

OU

mPickDate.setOnFocusChangeListener(new View.OnFocusChangeListener() {

    @Override
    public void onFocusChange(View v, boolean hasFocus) {
        showDialog(DATE_DIALOG_ID);

    }
});

Veja as diferenças por si mesmo. O problema é desde (como disse RickNotFred) TextView para exibir a data e editar através do DatePicker. O TextEdit não é usado para seu propósito principal. Se você quiser que o DatePicker reapareça, você precisa inserir delete (primeiro caso) ou desfocar (segundo caso).

Raio

Raymond Chenon
fonte
2
a menos que você adicione um onClickListener, que acabei de fazer junto com um onFocusChangeListener. Isso funcionará :-)
neteinstein
A segunda solução funcionou para mim, obrigado! :)
Celtik
10

Se você usar a ação OnClick em EditText como:

Java:

mEditInit = (EditText) findViewById(R.id.date_init);
mEditInit.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        showDialog(DATEINIT_DIALOG);
    }

});

ou kotlin:

editTextChooseDate.setOnClickListener {
        showDialog(DATEINIT_DIALOG)
    }

Então, funcionará perfeitamente se você colocar em xmluma EditTextdas seguintes linhas:

android: inputType = "none"
android: focusable = "false"
android: cursorVisible = "false"

Por exemplo:

<EditText
            android:id="@+id/date_init" 
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text=""
            android:hint="Select Date"
            android:inputType="none"
            android:focusable="false"
            android:cursorVisible="false"/>

ou para MaterialDesign

<com.google.android.material.textfield.TextInputLayout
        android:id="@+id/layoutEditTextChooseDate"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent">

    <com.google.android.material.textfield.TextInputEditText
            android:id="@+id/date_init" 
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text=""
            android:hint="Select Date"
            android:inputType="none"
            android:focusable="false"                      
            android:cursorVisible="false"/>

</com.google.android.material.textfield.TextInputLayout>
V.March
fonte
8

IMHO, discordo da declaração de RickNotFred:

Abrir uma caixa de diálogo quando um EditText obtém o foco parece uma interface não padrão.

Exibir uma caixa de diálogo para editar a data quando o usuário pressiona um EditText é muito semelhante ao padrão, que é exibir um teclado ou um teclado numérico. O fato de a data ser exibida com o EditText sinaliza ao usuário que a data pode ser alterada. Exibir a data como um TextView não editável sinaliza ao usuário que a data não pode ser alterada.

fishjd
fonte
7

Bom tópico. Bem, eu fiz isso. No arquivo XML:

<EditText
    ...
    android:editable="false"
    android:inputType="none" />

Em código Java:

txtDay.setOnClickListener(onOnClickEvent);
txtDay.setOnFocusChangeListener(onFocusChangeEvent);

private View.OnClickListener onOnClickEvent = new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        dpDialog.show();
    }
};
private View.OnFocusChangeListener onFocusChangeEvent = new View.OnFocusChangeListener() {
    @Override
    public void onFocusChange(View v, boolean hasFocus) {
        if (hasFocus)
            dpDialog.show();
    }
};
CoolMind
fonte
6

O seguinte funciona perfeitamente para mim.

Primeiro, defina a entrada do widget selecionador de data como 'nenhum' para evitar que o teclado virtual seja exibido:

<EditText android:inputType="none" ... ></EditText>

Em seguida, adicione esses ouvintes de evento para mostrar a caixa de diálogo que contém o selecionador de data:

// Date picker
EditText dateEdit = (EditText) findViewById(R.id.date);
dateOfBirthEdit.setOnTouchListener(new OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_UP) {
            showDialog(DIALOG_DATE_PICKER);
        }
        return false;
    }
});

dateEdit.setOnFocusChangeListener(new OnFocusChangeListener() {

    @Override
    public void onFocusChange(View v, boolean hasFocus) {
        if (hasFocus) {
            showDialog(DIALOG_DATE_PICKER);
        } else {
            dismissDialog(DIALOG_DATE_PICKER);
        }
    }
});

Uma última coisa. Para garantir que os dias, meses ou anos digitados sejam copiados corretamente do selecionador de data, ligue datePicker.clearFocus()antes de recuperar os valores, por exemplo, via getMonth().

Lukas Batteau
fonte
Correção simples: DispenseDialog antes de cada showDialog, só para ter certeza.
Lukas Batteau de
5

Isso funciona para mim:

mEditInit = (EditText) findViewById(R.id.date_init);
mEditInit.setKeyListener(null);
mEditInit.setOnFocusChangeListener(new View.OnFocusChangeListener() {
        @Override
        public void onFocusChange(View v, boolean hasFocus) {
            if(hasFocus)
            {
                mEditInit.callOnClick();
            }
        }
    });
mEditInit.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        showDialog(DATEINIT_DIALOG);
    }

});
Rahim Rahimov
fonte
3

Aqui está o que funcionou para mim

Definir editável como falso

<EditText android:id="@+id/dob"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="Date of Birth"
android:inputType="none"
android:editable="false"

/>

Em seguida, adicione um ouvinte de evento para OnFocusChange

private  View.OnFocusChangeListener onFocusChangeDOB= new View.OnFocusChangeListener() {

@Override
 public void onFocusChange(View v, boolean hasFocus) {
   if (hasFocus){
     showDialog(DATE_DIALOG_ID);
   }
 }
};
Matt
fonte
3
Cuidado com os telefones Motorola rodando Android 2.3.x. Se EditText estiver em algum lugar em uma área de rolagem, a Motorola moverá automaticamente o foco quando você rolar. Isso significa que você pode rolar para baixo e quando o EditText ganha foco, sua caixa de diálogo de data aparece, o que é surpreendente e ruim.
Eric Burke,
2

Como sugeriu Dillon Kearns, definir focalizável como falso funciona bem. Mas se o seu objetivo é cancelar o teclado quando EditText é clicado, você pode querer usar:

mEditText.setInputType(0);
imbrizi
fonte
2

Por que ninguém mencionou setOnTouchListener? Usar setOnTouchListeneré fácil e correto, e apenas retornar verdadeiro se o ouvinte tiver consumido o evento, falso caso contrário.

drakeet
fonte
0

O problema com as soluções que usam OnFocusChangeListener é que elas interpretam qualquer ganho de foco como um clique. Isso não é 100% correto: seu EditText pode ganhar foco de outra coisa que não um clique.

Se você se preocupa estritamente com o clique e deseja detectá-lo de forma consistente (independentemente do foco), você pode usar GestureDetector:

editText.setOnConsistentClickListener { /* do something */ }

fun EditText.setOnConsistentClickListener(doOnClick: (View) -> Unit) {
    val gestureDetector = GestureDetectorCompat(context, object : GestureDetector.SimpleOnGestureListener() {
        override fun onSingleTapUp(event: MotionEvent?): Boolean {
            doOnClick(this@setOnConsistentClickListener)
            return false
        }
    })

    this.setOnTouchListener { _, motionEvent -> gestureDetector.onTouchEvent(motionEvent) }
}
David Ferrand
fonte