简体   繁体   English

如何为 ImageButton 组合 OnClickListener 和 OnTouchListener

[英]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时我需要做一些事情 我试图创建一个同时实现OnClickListenerOnTouchListener的静态类

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. 我发现, TouchEventClickEvent更通用,因此首先调用它。

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.您可以结合使用GestureDetectorsetOnTouchListener来实现这一点,而不是基于距离/时间差异的方法。 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM