onTouch 和 onClick 没有正确触发
onTouch and onClick not triggering properly
我有 ReltiveLayout 和 ImageView 以及里面的 TextView。
所以我有两个事件监听器:
onClick
onTouch
我正在使用 9patch
作为图像。当我使用 onTouch 事件时,onClick 根本没有触发,而且 onTouch 也不能很好地工作。如果我禁用 onTouch 并保留 onClick,它会触发并更改 Activity。我想让 onTouch 和 onClick 一起工作。我要:
- 单击 RelativeLayout 时,它会显示选定的按钮 ImageView
- 否则显示普通按钮ImageView
- onClickListener 更改 activity。
这是我的代码:
StartBtn = (RelativeLayout) findViewById(R.id.StartBtn);
StartBtnImage = (ImageView) findViewById(R.id.StartBtnImage);
StartBtnText = (TextView) findViewById(R.id.StartBtnText);
StartBtn.setOnTouchListener(new TouchButton(StartBtnImage)); //Commenting this line makes the onClickListener work
StartBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
StartBtnImage.setImageResource(R.drawable.btn_selected);
Log.d("ButtonClick", "Done");
Intent myIntent = new Intent(MainMenu.this, Game.class);
startActivity(myIntent);
}
});
还有我的 TouchButton class:
public class TouchButton implements View.OnTouchListener {
ImageView IV;
public TouchButton(ImageView Image) {
IV = Image;
}
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
IV.setImageResource(R.drawable.btn_selected);
return true;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_OUTSIDE:
default:
IV.setImageResource(R.drawable.btn);
return false;
}
}
}
这是我的布局
<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" android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainMenu">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/MainMenuBg"
android:background="@drawable/main_menu_bg" />
<RelativeLayout
android:layout_width="250dp"
android:layout_height="75dp"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="130dp"
android:id="@+id/StartBtn"
android:clickable="true">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/StartBtnImage"
android:src="@drawable/btn" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="Start"
android:id="@+id/StartBtnText"
android:layout_centerVertical="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:singleLine="false"
android:gravity="center|center_vertical|center_horizontal"
android:textSize="50dp" />
</RelativeLayout>
我知道我不善于解释,所以这是一个视频: https://www.youtube.com/watch?v=PtdUsW-Dnqk
更新: 因为您不能在单个视图上使用多个侦听器 see link。
您可以在 TouchButton.class.
中实现 .setOnClickListener
的行为
public class TouchButton implements View.OnTouchListener {
ImageView IV;
public TouchButton(ImageView Image) {
IV = Image;
}
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
IV.setImageResource(R.drawable.btn_selected);
return true;
case MotionEvent.ACTION_UP:
switch(v.getId()){
case R.id.StartBtn:
IV.setImageResource(R.drawable.btn_selected);
Log.d("ButtonClick", "Done");
Intent myIntent = new Intent(MainMenu.this, Game.class);
startActivity(myIntent);
break;
return true;
case MotionEvent.ACTION_OUTSIDE:
default:
IV.setImageResource(R.drawable.btn);
return false;
}
}
}
是的,您可以在单个视图上使用多个侦听器(如果不可能,那就会有问题)。
基本上,您视图的触摸事件在点击事件之前被触发。
如果触摸侦听器消耗事件(return来自onTouch 的 为真,则不会调用点击侦听器。
如果您从 onTouch 侦听器 return true,那么您 不会使用 事件(returning false)并且任何底层侦听器都将像 onClick 侦听器一样被调用。
这里有两个侦听器附加到单个视图(一个按钮)的示例:
btnStart = (Button) findViewById(R.id.btn_start);
btnStart.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
Log.d("stack", "TOUCH EVENT");
return false;
}
});
btnStart.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d("stack", "CLICK EVENT");
Toast.makeText(getApplicationContext(), "start game...", 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" android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">
<Button
android:id="@+id/btn_start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="start btn"/>
</RelativeLayout>
在日志中,当您触摸按钮时,您会看到 TOUCH EVENT 在 CLICK EVENT 之前写入,因为 onTouch 侦听器不使用该事件(returns false)并首先被调用。
我建议您阅读 Android 中有关触摸传播的文档,并查看 Dave Smith 关于此主题的有用 video。
最后,您应该查看 xml 中的小部件状态,以便在单击或聚焦时更改它们的外观,...查看 there
希望对您有所帮助。
这是我的代码,希望能解决你的问题
`
public boolean onTouch(View v, MotionEvent 事件) {
int index = event.getActionIndex();
int action = event.getActionMasked();
int pointerId = event.getPointerId(index);
switch (action) {
case MotionEvent.ACTION_DOWN:
if (mVelocityTracker == null) {
// Retrieve a new VelocityTracker object to watch the
// velocity of a motion.
mVelocityTracker = VelocityTracker.obtain();
//getrawX, getrawY
startX = event.getRawX();
startY = event.getRawY();
// Add a user's movement to the tracker.
mVelocityTracker.addMovement(event);
} else {
// Reset the velocity tracker back to its initial state.
mVelocityTracker.clear();
}
break;
case MotionEvent.ACTION_MOVE:
mVelocityTracker.addMovement(event);
mVelocityTracker.computeCurrentVelocity(1000);
velocityX = mVelocityTracker.getXVelocity(pointerId);
velocityY = mVelocityTracker.getXVelocity(pointerId);
diffX = event.getRawX() - startX;
diffY = event.getRawY() - startY;
if(Math.abs(diffX)> 10) {
startX = event.getRawX();
if (diffX < 0 && velocityX != 0) {
swipeLeft(diffX, velocityX);
} else {
swipeRight(diffX, velocityX);
}
}
if(Math.abs(diffY)> 10) {
startY = event.getRawY();
if (diffY < 0 && velocityY != 0) {
swipeTop(diffY, velocityY);
} else {
swipeBottom(Math.abs(diffY) / velocityY);
}
}
break;
case MotionEvent.ACTION_UP:
if(distanceX == 0){
Intent intent = new Intent(context, MainActivity.class);
intent.putExtra("SET_ID", listSet.get(getAdapterPosition()).getId());
itemView.getContext().startActivity(intent);
break;
}
case MotionEvent.ACTION_CANCEL:
checkDis();
// Return a VelocityTracker object back to be re-used by others.
try {
mVelocityTracker.recycle();
mVelocityTracker = null;
}catch (Exception e){
Log.d("exeption", e.getMessage());
}
break;
}
return true;
}
});
}
// check action up then cancel
//purpose: scroll to initalize status if the behind layout not been opened
private void checkDis(){
if(distanceX<=0 && distanceX > -200){
scrollView(cvSetItem, 0,(long) Math.abs(distanceX)*600/150);
distanceX = 0;
}
}
private void scrollView( View v, float toX, long duration){
// do something
}
private void swipeLeft(float diff, float velo) {
distanceX += diff;
Log.d("distance left", " " + distanceX);
if(distanceX>-200 && distanceX <0) {
scrollView(cvSetItem,distanceX, (long) (diff/velo));
}else {
distanceX = -200;
scrollView(cvSetItem,distanceX, 0);
}
}
private void swipeRight(float diff, float velo) {
Log.d("distance right", " " + distanceX);
distanceX+=diff;
if(distanceX<0){
scrollView(cvSetItem,distanceX, (long) Math.abs(diff/velo));
}else {
distanceX =0;
}
}
private void swipeTop(float diffY, float velo) {
}
private void swipeBottom(float duration) {
}`
刚设置
@Override
public boolean onDown(MotionEvent e) {
return false;
}
您的 touchListener
和 clickListener
都可以正常工作
我有 ReltiveLayout 和 ImageView 以及里面的 TextView。
所以我有两个事件监听器:
onClick
onTouch
我正在使用 9patch
作为图像。当我使用 onTouch 事件时,onClick 根本没有触发,而且 onTouch 也不能很好地工作。如果我禁用 onTouch 并保留 onClick,它会触发并更改 Activity。我想让 onTouch 和 onClick 一起工作。我要:
- 单击 RelativeLayout 时,它会显示选定的按钮 ImageView
- 否则显示普通按钮ImageView
- onClickListener 更改 activity。
这是我的代码:
StartBtn = (RelativeLayout) findViewById(R.id.StartBtn);
StartBtnImage = (ImageView) findViewById(R.id.StartBtnImage);
StartBtnText = (TextView) findViewById(R.id.StartBtnText);
StartBtn.setOnTouchListener(new TouchButton(StartBtnImage)); //Commenting this line makes the onClickListener work
StartBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
StartBtnImage.setImageResource(R.drawable.btn_selected);
Log.d("ButtonClick", "Done");
Intent myIntent = new Intent(MainMenu.this, Game.class);
startActivity(myIntent);
}
});
还有我的 TouchButton class:
public class TouchButton implements View.OnTouchListener {
ImageView IV;
public TouchButton(ImageView Image) {
IV = Image;
}
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
IV.setImageResource(R.drawable.btn_selected);
return true;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_OUTSIDE:
default:
IV.setImageResource(R.drawable.btn);
return false;
}
}
}
这是我的布局
<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" android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainMenu">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/MainMenuBg"
android:background="@drawable/main_menu_bg" />
<RelativeLayout
android:layout_width="250dp"
android:layout_height="75dp"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="130dp"
android:id="@+id/StartBtn"
android:clickable="true">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/StartBtnImage"
android:src="@drawable/btn" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="Start"
android:id="@+id/StartBtnText"
android:layout_centerVertical="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:singleLine="false"
android:gravity="center|center_vertical|center_horizontal"
android:textSize="50dp" />
</RelativeLayout>
我知道我不善于解释,所以这是一个视频: https://www.youtube.com/watch?v=PtdUsW-Dnqk
更新: 因为您不能在单个视图上使用多个侦听器 see link。 您可以在 TouchButton.class.
中实现.setOnClickListener
的行为
public class TouchButton implements View.OnTouchListener {
ImageView IV;
public TouchButton(ImageView Image) {
IV = Image;
}
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
IV.setImageResource(R.drawable.btn_selected);
return true;
case MotionEvent.ACTION_UP:
switch(v.getId()){
case R.id.StartBtn:
IV.setImageResource(R.drawable.btn_selected);
Log.d("ButtonClick", "Done");
Intent myIntent = new Intent(MainMenu.this, Game.class);
startActivity(myIntent);
break;
return true;
case MotionEvent.ACTION_OUTSIDE:
default:
IV.setImageResource(R.drawable.btn);
return false;
}
}
}
是的,您可以在单个视图上使用多个侦听器(如果不可能,那就会有问题)。
基本上,您视图的触摸事件在点击事件之前被触发。 如果触摸侦听器消耗事件(return来自onTouch 的 为真,则不会调用点击侦听器。 如果您从 onTouch 侦听器 return true,那么您 不会使用 事件(returning false)并且任何底层侦听器都将像 onClick 侦听器一样被调用。
这里有两个侦听器附加到单个视图(一个按钮)的示例:
btnStart = (Button) findViewById(R.id.btn_start);
btnStart.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
Log.d("stack", "TOUCH EVENT");
return false;
}
});
btnStart.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d("stack", "CLICK EVENT");
Toast.makeText(getApplicationContext(), "start game...", 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" android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">
<Button
android:id="@+id/btn_start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="start btn"/>
</RelativeLayout>
在日志中,当您触摸按钮时,您会看到 TOUCH EVENT 在 CLICK EVENT 之前写入,因为 onTouch 侦听器不使用该事件(returns false)并首先被调用。
我建议您阅读 Android 中有关触摸传播的文档,并查看 Dave Smith 关于此主题的有用 video。
最后,您应该查看 xml 中的小部件状态,以便在单击或聚焦时更改它们的外观,...查看 there
希望对您有所帮助。
这是我的代码,希望能解决你的问题 ` public boolean onTouch(View v, MotionEvent 事件) {
int index = event.getActionIndex();
int action = event.getActionMasked();
int pointerId = event.getPointerId(index);
switch (action) {
case MotionEvent.ACTION_DOWN:
if (mVelocityTracker == null) {
// Retrieve a new VelocityTracker object to watch the
// velocity of a motion.
mVelocityTracker = VelocityTracker.obtain();
//getrawX, getrawY
startX = event.getRawX();
startY = event.getRawY();
// Add a user's movement to the tracker.
mVelocityTracker.addMovement(event);
} else {
// Reset the velocity tracker back to its initial state.
mVelocityTracker.clear();
}
break;
case MotionEvent.ACTION_MOVE:
mVelocityTracker.addMovement(event);
mVelocityTracker.computeCurrentVelocity(1000);
velocityX = mVelocityTracker.getXVelocity(pointerId);
velocityY = mVelocityTracker.getXVelocity(pointerId);
diffX = event.getRawX() - startX;
diffY = event.getRawY() - startY;
if(Math.abs(diffX)> 10) {
startX = event.getRawX();
if (diffX < 0 && velocityX != 0) {
swipeLeft(diffX, velocityX);
} else {
swipeRight(diffX, velocityX);
}
}
if(Math.abs(diffY)> 10) {
startY = event.getRawY();
if (diffY < 0 && velocityY != 0) {
swipeTop(diffY, velocityY);
} else {
swipeBottom(Math.abs(diffY) / velocityY);
}
}
break;
case MotionEvent.ACTION_UP:
if(distanceX == 0){
Intent intent = new Intent(context, MainActivity.class);
intent.putExtra("SET_ID", listSet.get(getAdapterPosition()).getId());
itemView.getContext().startActivity(intent);
break;
}
case MotionEvent.ACTION_CANCEL:
checkDis();
// Return a VelocityTracker object back to be re-used by others.
try {
mVelocityTracker.recycle();
mVelocityTracker = null;
}catch (Exception e){
Log.d("exeption", e.getMessage());
}
break;
}
return true;
}
});
}
// check action up then cancel
//purpose: scroll to initalize status if the behind layout not been opened
private void checkDis(){
if(distanceX<=0 && distanceX > -200){
scrollView(cvSetItem, 0,(long) Math.abs(distanceX)*600/150);
distanceX = 0;
}
}
private void scrollView( View v, float toX, long duration){
// do something
}
private void swipeLeft(float diff, float velo) {
distanceX += diff;
Log.d("distance left", " " + distanceX);
if(distanceX>-200 && distanceX <0) {
scrollView(cvSetItem,distanceX, (long) (diff/velo));
}else {
distanceX = -200;
scrollView(cvSetItem,distanceX, 0);
}
}
private void swipeRight(float diff, float velo) {
Log.d("distance right", " " + distanceX);
distanceX+=diff;
if(distanceX<0){
scrollView(cvSetItem,distanceX, (long) Math.abs(diff/velo));
}else {
distanceX =0;
}
}
private void swipeTop(float diffY, float velo) {
}
private void swipeBottom(float duration) {
}`
刚设置
@Override
public boolean onDown(MotionEvent e) {
return false;
}
您的 touchListener
和 clickListener
都可以正常工作