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.


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() {...});

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).


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!


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" />

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


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>

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.


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();
    }
};

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().


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);
    }

});

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);
   }
 }
};

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);

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.


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) }
}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.