onClick 事件未触发 |安卓

2022-01-09 00:00:00 onclick android java

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

I made a very simple test application with one activity and one layout. The onClick doesn't trigger the first time it is pressed, as it should.

活动:

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.我需要这个基本功能,但一直想不出一种让它工作的方法.想法?

If you run this application, and click on the second editText and then back on the first one, it will not trigger the onClick. You can keep selecting back and forth and it will not trigger the onClick at all. I need this basic functionality, but haven't been able to think of a way to get it to work. Ideas?

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

I have tried all of the methods recommended on my API level 16 physical device and my API level 8 emulator, but I get the same problem.

editText1 获得焦点并被点击时,onClick 方法就会触发.如果聚焦 editText2,然后单击 editText1,它不会触发.大问题.

When editText1 is focused and is clicked on, then the onClick method fires. If editText2 is focussed, and then editText1 is clicked, it doesn't fire. Big problem.

推荐答案

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

Overview, when a user interacts with any UI component the various listeners are called in a top-down order. If one of the higher priority listeners "consumes the event" then the lower listeners will not be called.

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

In your case these three listeners are called in order:

  1. OnTouchListener
  2. OnFocusChangeListener
  3. OnClickListener

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

The first time the user touches an EditText it receives focus so that the user can type. The action is consumed here. Therefor the lower priority OnClickListener is not called. Each successive touch doesn't change the focus so these events trickle down to the OnClickListener.

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

Buttons (and other such components) don't receive focus from a touch event, that's why the OnClickListener is called every time.

基本上,您有三个选择:

  1. 自己实现一个 OnTouchListener:

  1. Implement an OnTouchListener by itself:

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.

This will execute every time the EditText is touched. Notice that the listener returns false, this allows the event to trickle down to the built-in OnFocusChangeListener which changes the focus so the user can type in the EditText.

与 OnClickListener 一起实现 OnFocusChangeListener:

Implement an OnFocusChangeListener along with the OnClickListener:

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

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

This listener catches the first touch event when the focus is changed while your OnClickListener catches every other event.

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

(This isn't a valid answer here, but it is a good trick to know.) Set the focusable attribute to false in your XML:

android:focusable="false"

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

Now the OnClickListener will fire every time it is clicked. But this makes the EditText useless since the user can no longer enter any text...

注意:

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

希望有帮助!

相关文章