我用一个活动和一个布局制作了一个非常简单的测试应用程序。第一次按下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
,则不会触发。大问题。
答案 0 :(得分:179)
概述当用户与任何UI组件交互时,将以自上而下的顺序调用各种侦听器。如果其中一个较高优先级的侦听器“消耗该事件”,那么较低的侦听器将不会被调用。
在您的情况下,按顺序调用这三个侦听器:
用户第一次触摸EditText时,它会收到焦点,以便用户可以输入。 此处消耗操作。因此不会调用优先级较低的OnClickListener。每次连续触摸都不会改变焦点,因此这些事件会逐渐变为OnClickListener。
按钮(以及其他此类组件)不会从触摸事件中获得焦点,这就是每次调用OnClickListener的原因。
基本上,您有三种选择:
单独实现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。
实现OnFocusChangeListener和OnClickListener:
ed1.setOnFocusChangeListener(new OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if(hasFocus)
editTextClicked(); // Instead of your Toast
}
});
当OnClickListener捕获所有其他事件时,此侦听器捕获第一个触摸事件。
(这不是一个有效的答案,但这是一个很好的技巧。)在您的XML中将focusable属性设置为false
:
android:focusable="false"
现在,OnClickListener将在每次点击时触发。但这会使EditText变得无用,因为用户无法再输入任何文本......
注意:强>
getApplicationContext()
可能会造成内存泄漏。除非绝对必要,否则一个好习惯是避免使用它。您可以安全地使用v.getContext()
。
希望有所帮助!
答案 1 :(得分:5)
使编辑文字可点击..
在XML中android:clickable="true"
或在代码中
ed1.setClickable(true);
然后做
ed1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(getBaseContext(), "1",Toast.LENGTH_SHORT).show();
}
});
答案 2 :(得分:4)
我可能来不及派对了,但是这里有一段代码剪辑修复了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;
}
});
答案 3 :(得分:2)
这是因为第一次点击使焦点进入视图。下一次点击会触发点击。
如果要动态膨胀视图,请执行以下操作:
android:clickable="true"
android:focusable="false"
android:focusableInTouchMode="false"
如果这不起作用,请尝试在父视图上应用它。
答案 4 :(得分: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>
答案 5 :(得分:0)
在我遇到这种情况时,我花了一分钟时间想出这一点。我的ImageButton
setOnClickListener
和onClick
似乎无法启动,然后我意识到它实际上位于我的xml布局中的另一个元素下面,所以我转过身来:
<RelativeLayout>
<ImageButton>
<LinearLayout></LinearLayout>
</RelativeLayout>
进入这个:
<RelativeLayout>
<LinearLayout></LinearLayout>
<ImageButton>
</RelativeLayout>
突然之间,ImageButton没有与其他布局重叠,因为它现在稍后被添加到父布局中,现在位于顶部并且每次都有效。祝你好运,当基本的东西突然停止工作时总是很有趣
答案 6 :(得分:0)
避免使用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
第一次正常运行。
答案 7 :(得分:0)
这是使用日期选择器的最简单方法。
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;
}
});
答案 8 :(得分:0)
我从两个自定义扩展功能开始:
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
}