[英]How to combine OnClickListener and OnTouchListener for an ImageButton
I need to do something when the user clicks the ImageButton
I've tried to create a static class that implements both OnClickListener
and OnTouchListener
当用户单击
ImageButton
时我需要做一些事情 我试图创建一个同时实现OnClickListener
和OnTouchListener
的静态类
static class ClickListenerForScrolling implements OnClickListener, OnTouchListener
that has the following methods:具有以下方法:
@Override
public void onClick(View v)
and和
@Override
public boolean onTouch(View arg0, MotionEvent arg1)
The whole idea behind this is to change the image source of the ImageButton
when the user touches it, and perform a task when the user clicks this button.这背后的整个想法是在用户触摸时更改
ImageButton
的图像源,并在用户单击此按钮时执行任务。 Can anybody give me a hint on how to do this?任何人都可以提示我如何执行此操作吗?
Since both actions consist of the gestures "put finger on screen - lift finger from screen" you can't determine if it was touch action or a click action. 由于这两个动作都包括“将手指放在屏幕上 - 手指从屏幕上抬起”的手势,因此无法确定是触摸动作还是点击动作。 So if you implement both listeners on this image button, a touch/click will change the picture AND press the button.
因此,如果您在此图像按钮上实现两个侦听器,则触摸/单击将更改图片并按下按钮。 Not sure if there is a determined order of these events...
不确定这些事件是否有确定的顺序......
However, if you want to separate these events, you will either need to define to a different gesture to one of the actions (like wiping to change picture), or create different areas who handle the events, for example the image doesn't fit the whole button and the free area serves as button click area. 但是,如果要分离这些事件,则需要为其中一个操作定义不同的手势(例如擦除以更改图片),或创建处理事件的不同区域,例如图像不适合整个按钮和空闲区域用作按钮点击区域。
HTH HTH
Update: 更新:
I figured out, that a TouchEvent
is more general than a ClickEvent
thus it is called first. 我发现,
TouchEvent
比ClickEvent
更通用,因此首先调用它。
public abstract boolean onTouch (View v, MotionEvent event)
This returns true, if the listener has consumed the event, false otherwise. 如果侦听器已使用该事件,则返回true,否则返回false。 So you can decide in your implementation if the Event should also be handled by OnClickListener, then just return
false
. 因此,您可以在实现中决定是否也应该由OnClickListener处理事件,然后返回
false
。
The onTouchListener
is able to handle both movements. onTouchListener
能够处理这两种动作。
Switch
between event.action()
values to obtain MotionEvent
. 在
event.action()
值之间Switch
以获取MotionEvent
。
case MotionEvent.ACTION_DOWN
: is the first finger impact. case MotionEvent.ACTION_DOWN
:是第一次手指撞击。
case MotionEvent.ACTION_UP
: is when the finger goes away. case MotionEvent.ACTION_UP
:是手指消失的时候。
You'll have to set the impact point on ACTION_DOWN
. 您必须在
ACTION_DOWN
上设置影响点。
TheImpactPoint=event.getX();
And then obtain the distance with ACTION_UP
然后用
ACTION_UP
获取距离
float distance =TheImpactPoint-event.getX();
If distance = 0
then there is a click, otherwise it would be more or less than zero depending on gesture. If distance = 0
则存在咔嗒声,否则根据手势它将大于或小于零。
So this is the way to use the click event without a real click event and using only the onTouchListener
. 因此,这是在没有实际点击事件的情况下使用click事件并仅使用
onTouchListener
。
Hope will be useful. 希望会有用。
Use this code: 使用此代码:
public class GestureHelper implements OnTouchListener {
private final GestureDetector mGestureDetector;
public GestureHelper(Context context) {
mGestureDetector = new GestureDetector(context, new GestureListener(this));
}
public void onSwipeRight() {
};
public void onSwipeLeft() {
};
public void onSwipeTop() {
};
public void onSwipeBottom() {
};
public void onDoubleTap() {
};
public void onClick() {
};
@Override
public boolean onTouch(View v, MotionEvent event) {
return mGestureDetector.onTouchEvent(event);
}
private static final class GestureListener extends SimpleOnGestureListener {
private static final int SWIPE_THRESHOLD = 100;
private static final int SWIPE_VELOCITY_THRESHOLD = 100;
private GestureHelper mHelper;
public GestureListener(GestureHelper helper) {
mHelper = helper;
}
@Override
public boolean onDown(MotionEvent e) {
return true;
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
mHelper.onClick();
return true;
}
@Override
public boolean onDoubleTap(MotionEvent e) {
mHelper.onDoubleTap();
return true;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
boolean result = false;
try {
float diffY = e2.getY() - e1.getY();
float diffX = e2.getX() - e1.getX();
if (Math.abs(diffX) > Math.abs(diffY)) {
if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
if (diffX > 0) {
mHelper.onSwipeRight();
} else {
mHelper.onSwipeLeft();
}
}
} else {
if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) {
if (diffY > 0) {
mHelper.onSwipeBottom();
} else {
mHelper.onSwipeTop();
}
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
return result;
}
}
}
Extend this class and use like this... 扩展这个类并像这样使用...
view.setOnTouchListener(new SomeYourGestureHelper(context, someParameters));
使用return false
而不是return true
There are many solutions for this problem, the best one for me is to eliminate totally the setOnClickListener and inside the onTouchListener do check if the action is ACTION_UP and then inside that check if the last before that is ACTION_DOWN: 这个问题有很多解决方案,对我来说最好的方法是完全消除setOnClickListener,并在onTouchListener内部检查操作是否为ACTION_UP,然后在内部检查前一个是否为ACTION_DOWN:
case MotionEvent.ACTION_UP:
if (lastAction == MotionEvent.ACTION_DOWN) {
//code for click
.
.
lastAction = event.getAction();
}
lastAction is int and I update it at the end of each ACTION lastAction是int,我在每个ACTION结束时更新它
Rather than distance / time diff based approaches, You can make use of GestureDetector
in combination with setOnTouchListener
to achieve this.您可以结合使用
GestureDetector
和setOnTouchListener
来实现这一点,而不是基于距离/时间差异的方法。 GestureDetector
would detect the click while you can use OnTouchListener
for other touch based events, eg detecting drag. GestureDetector
会检测点击,而您可以将OnTouchListener
用于其他基于触摸的事件,例如检测拖动。
Here is a sample code for reference:下面是一个示例代码供参考:
Class MyCustomView() {
fun addClickAndTouchListener() {
val gestureDetector = GestureDetector(
context,
object : GestureDetector.SimpleOnGestureListener() {
override fun onSingleTapConfirmed(e: MotionEvent?): Boolean {
// Add your onclick logic here
return true
}
}
)
setOnTouchListener { view, event ->
when {
gestureDetector.onTouchEvent(event) -> {
// Your onclick logic would be triggered through SimpleOnGestureListener
return@setOnTouchListener true
}
event.action == MotionEvent.ACTION_DOWN -> {
// Handle touch event
return@setOnTouchListener true
}
event.action == MotionEvent.ACTION_MOVE -> {
// Handle drag
return@setOnTouchListener true
}
event.action == MotionEvent.ACTION_UP -> {
// Handle Drag over
return@setOnTouchListener true
}
else -> return@setOnTouchListener false
}
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.