59

我用一个活动和一个布局制作了一个非常简单的测试应用程序。onClick不会在第一次按下时触发,因为它应该。

活动:

package com.example.mytest;

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;

public class MainActivity extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        final EditText ed1 = (EditText) findViewById(R.id.editText1);

        ed1.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub

                Toast.makeText(getApplicationContext(), "1", Toast.LENGTH_LONG)
                        .show();

            }

        });
    }

}

布局:

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

    <EditText
        android:id="@+id/editText1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:ems="10" >

        <requestFocus />
    </EditText>

    <EditText
        android:id="@+id/editText2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_below="@+id/editText1"
        android:ems="10" />

</RelativeLayout>

如果您运行此应用程序,然后单击第二个editText然后返回第一个,它不会触发onClick. 您可以继续来回选择,它根本不会触发onClick。我需要这个基本功能,但一直想不出一种让它工作的方法。想法?

注意

我已经尝试了在我的 API 级别 16 物理设备和我的 API 级别 8 模拟器上推荐的所有方法,但我遇到了同样的问题。

澄清

editText1被聚焦并被点击时,该onClick方法被触发。如果editText2被聚焦,然后editText1被点击,它不会触发。大问题。

4

9 回答 9

213

概述,当用户与任何 UI 组件交互时,会按自上而下的顺序调用各种侦听器。如果较高优先级的侦听器之一“消耗事件”,则不会调用较低的侦听器。

在您的情况下,这三个侦听器按顺序调用:

  1. OnTouchListener
  2. OnFocusChangeListener
  3. OnClickListener

用户第一次触摸 EditText 时,它会获得焦点,以便用户可以键入。动作在这里被消耗。 因此不调用较低优先级的 OnClickListener。每次连续的触摸都不会改变焦点,因此这些事件会向下传递到 OnClickListener。

按钮(和其他此类组件)不会从触摸事件中获得焦点,这就是每次调用 OnClickListener 的原因。

基本上,您有三个选择:

  1. 自己实现一个 OnTouchListener:

    ed1.setOnTouchListener(new OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            if(MotionEvent.ACTION_UP == event.getAction())
                editTextClicked(); // Instead of your Toast
            return false;
        }
    });
    

    每次触摸 EditText 时都会执行此操作。请注意,侦听器返回false,这允许事件向下传播到内置的 OnFocusChangeListener,它会更改焦点,以便用户可以在 EditText 中键入。

  2. 实现 OnFocusChangeListener 和 OnClickListener:

    ed1.setOnFocusChangeListener(new OnFocusChangeListener() {
        @Override
        public void onFocusChange(View v, boolean hasFocus) {
            if(hasFocus)
                editTextClicked(); // Instead of your Toast
        }
    });
    

    当您的 OnClickListener 捕获所有其他事件时,此侦听器会在焦点更改时捕获第一个触摸事件。

  3. (这不是一个有效的答案,但这是一个很好的技巧。)false在你的 XML 中设置 focusable 属性:

    android:focusable="false"
    

    现在 OnClickListener 将在每次单击时触发。但这使得 EditText 无用,因为用户不能再输入任何文本......

笔记:

getApplicationContext()会造成内存泄漏。一个好习惯是避免使用它,除非绝对必要。您可以安全地使用v.getContext()

希望有帮助!

于 2012-08-03T16:43:26.097 回答
5

使编辑文本可点击。在 XMLandroid:clickable="true" 或代码中

ed1.setClickable(true);

然后做

ed1.setOnClickListener(new OnClickListener() {

    @Override
    public void onClick(View v) {
      Toast.makeText(getBaseContext(), "1",Toast.LENGTH_SHORT).show();
    }
  });
于 2012-08-03T06:47:18.703 回答
5

我参加聚会可能为时已晚,但这里有一个代码被剪断,它解决了 onClick() 没有被调用的问题:

ed1.setOnTouchListener(new OnTouchListener() {

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_UP && !v.hasFocus()) {
            // onClick() is not called when the EditText doesn't have focus,
            // onFocusChange() is called instead, which might have a different 
            // meaning. This condition calls onClick() when click was performed
            // but wasn't reported. Condition can be extended for v.isClickable()
            // or v.isEnabled() if needed. Returning false means that everything
            // else behaves as before.
            v.performClick();
        }
        return false;
    }
});
于 2016-05-05T13:36:16.533 回答
4

发生这种情况是因为第一次点击获得了视图的焦点。下一次点击触发点击。

如果您要动态扩展视图,请执行以下操作:

android:clickable="true"
android:focusable="false"
android:focusableInTouchMode="false"

如果这不起作用,请尝试在父视图上应用它。

于 2017-05-04T08:28:37.690 回答
1

它是使用日期选择器最简单的方法。

private DatePickerDialog datePickerDialog;
EditText etJoiningDate;
etJoiningDate=(EditText)findViewById(R.id.etJoiningDate);

etJoiningDate.setOnTouchListener(new View.OnTouchListener() {

    @Override
    public boolean onTouch(View v, MotionEvent event) {

        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:

                final Calendar cldr = Calendar.getInstance();
                int day = cldr.get(Calendar.DAY_OF_MONTH);
                int month = cldr.get(Calendar.MONTH);
                int year = cldr.get(Calendar.YEAR);
                // date picker dialog
                datePickerDialog = new DatePickerDialog(TestActivity.this,
                        new DatePickerDialog.OnDateSetListener() {
                            @Override
                            public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
                                etJoiningDate.setText(dayOfMonth + "/" + (monthOfYear + 1) + "/" + year);
                            }
                        }, year, month, day);
                datePickerDialog.show();

                break;
        }


        return false;
    }


});
于 2018-05-03T05:45:57.960 回答
0
public class TestProject extends Activity implements OnClickListener {
TextView txtmsg;
EditText ed1, ed2;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    txtmsg = (TextView) findViewById(R.id.txtmsg);
    ed1 = (EditText) findViewById(R.id.edt1);
    ed2 = (EditText) findViewById(R.id.edt2);

    ed1.setOnClickListener(this);
    ed2.setOnClickListener(this);
}

@Override
public void onClick(View v) {


    if(v==ed1){
        txtmsg.setText("1");
        Toast.makeText(this, "first",Toast.LENGTH_SHORT).show();
    }
    if(v==ed2){
        txtmsg.setText("2");
        Toast.makeText(this, "second",Toast.LENGTH_SHORT).show();
    }

}

}

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

    <EditText
        android:id="@+id/edt1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:ems="10" />

    <EditText
        android:id="@+id/edt2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_below="@+id/edt1"
        android:layout_marginTop="14dp"
        android:ems="10" />

    <TextView
        android:id="@+id/txtmsg"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignRight="@+id/edt2"
        android:layout_below="@+id/edt2"
        android:layout_marginRight="22dp"
        android:layout_marginTop="160dp"
        android:textAppearance="?android:attr/textAppearanceLarge" />

</RelativeLayout>
于 2012-08-03T10:12:56.553 回答
0

当这发生在我身上时,我花了一分钟才弄清楚这一点。我ImageButton的 a setOnClickListenerandonClick似乎没有触发,然后我意识到它实际上在我的 xml 布局中的另一个元素下面,所以我转了这个:

 <RelativeLayout>
     <ImageButton>
     <LinearLayout></LinearLayout>
 </RelativeLayout>

进入这个:

 <RelativeLayout>
     <LinearLayout></LinearLayout>
     <ImageButton>
 </RelativeLayout>

突然之间,ImageButton 没有被其他布局重叠,因为它后来被添加到父布局中,并且现在位于顶部并且每次都可以使用。祝你好运,当基本的东西突然停止工作时总是很有趣

于 2015-09-20T04:09:24.617 回答
0

避免使用 a FocusChangeListener,因为当你真的不需要它时(例如,当你进入一个活动时)它会表现得不规律。只需像这样设置OnTouchListener一个OnClickListener

@Override
public boolean onTouch(View view, MotionEvent event) {
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            view.requestFocus();
            break;
    }
    return false;
}

这将导致您的 EditText 首先获得焦点,并且您onClick的第一次正常运行。

于 2016-11-07T19:37:41.453 回答
0

简单、可重用的 Kotlin 解决方案

我从两个自定义扩展功能开始:

val MotionEvent.up get() = action == MotionEvent.ACTION_UP

fun MotionEvent.isIn(view: View): Boolean {
    val rect = Rect(view.left, view.top, view.right, view.bottom)
    return rect.contains((view.left + x).toInt(), (view.top + y).toInt())
}

然后听一下 Edittext 上的内容。仅当初始 ACTION_DOWN 事件最初在 Edittext 上时才会触发,并且仍然存在。

myEdittext.setOnTouchListener { view, motionEvent ->
    if (motionEvent.up && motionEvent.isIn(view)) {
        // Talk your action here
    }
    false
}
于 2020-01-31T02:14:59.427 回答