LongClick事件发生得太快了。如何增加触发它所需的点击时间?

时间:2011-10-28 19:59:18

标签: android event-handling

在我正在处理的应用程序中,我要求用户必须点击&在某个动作发生之前将某个组件保留一段时间。

我目前正在使用OnLongClickListener来监听longclick,但我发现触发OnLongClick事件的点击时间太短。

例如,假设LongClick事件在400ms单击后触发,但我希望用户必须单击&在事件触发前保持1200ms。

有什么方法可以配置LongClick事件以要求更长的点击次数?
或者是否有另一种构造可以让我倾听更长的点击次数?

8 个答案:

答案 0 :(得分:18)

无法更改onLongClick事件的计时器,它由android本身管理。

可能的是使用.setOnTouchListener()。

然后在MotionEvent是ACTION_DOWN时注册 注意变量中的当前时间 然后,当注册具有ACTION_UP的MotionEvent并且current_time - actionDown时间> 1200毫秒然后做点什么。

非常好:

Button button = new Button();
long then = 0;
    button.setOnTouchListener(new OnTouchListener() {

        @Override
        public boolean onTouch(View v, MotionEvent event) {
            if(event.getAction() == MotionEvent.ACTION_DOWN){
                then = (Long) System.currentTimeMillis();
            }
            else if(event.getAction() == MotionEvent.ACTION_UP){
                if(((Long) System.currentTimeMillis() - then) > 1200){
                    return true;
                }
            }
            return false;
        }
    })

答案 1 :(得分:3)

我在Rohan :)的帮助下制定了一个解决方案 我根据自己的要求调整了答案。

当用户按下按钮时,启动一个线程。线程为我所需的延迟休眠,然后当它唤醒时,它会执行我需要它执行的任何代码。当用户放手时,线程被杀死。这实现了我想要的,因为如果用户在线程唤醒之前放开,则线程被中断并且不会发生操作。

我喜欢这种方法,因为它可以让我在延迟时间后立即执行我的业务逻辑,这很好,因为我可以给用户一些反馈,让他们知道他们推得足够长(电话可以振动,因为例子)。
这种方法的缺点是:用户在您运行所需操作时放开按钮,并在完成所有操作之前终止线程。对我来说这不是一个大问题,因为我的业务逻辑很少;它只是为其他一些类处理一个事件。如果操作未完全完成,则用户必须重试。

代码比我想要的时间长一些,但如果这是您应用程序中的常见功能,那么它很容易重复使用。这是一个代码示例:

protected class MyLongClickListener implements View.OnTouchListener {
    private Thread longClickSensor;

    public boolean onTouch(View view, MotionEvent event) {
        // If the user is pressing down and there is no thread, make one and start it
        if (event.getAction() == MotionEvent.ACTION_DOWN && longClickSensor == null) {
            longClickSensor = new Thread(new MyDelayedAction());
            longClickSensor.start();
        }
        // If the user has let go and there was a thread, stop it and forget about the thread
        if (event.getAction() == MotionEvent.ACTION_UP && longClickSensor != null) {
            longClickSensor.interrupt();
            longClickSensor = null;
        }
        return false;
    }

    private class MyDelayedAction implements Runnable {
        private final long delayMs = 1200;

        public void run() {
            try {
                Thread.sleep(delayMs); // Sleep for a while
                doBusinessLogic();     // If the thread is still around after the sleep, do the work
            } catch (InterruptedException e) { return; }
        }
        private void doBusinessLogic() {
            // Make sure this logic is as quick as possible, or delegate it to some other class
            // through Broadcasted Intents, because if the user lets go while the work is happenening,
            // the thread will be interrupted.
        }
    }
}

答案 2 :(得分:3)

这是我发现实现此行为的最简单方法。它比目前接受的答案有几个优点。

  1. 通过检查view.isPressed,如果触摸事件离开视图,我们会确保不会触发onClickonLongClick。这模仿了系统的默认onClickonLongClick行为。
  2. 该事件已存储时间信息,因此无需在ACTION_DOWN上存储开始时间或自行计算ACTION_UP上的当前时间。这意味着我们可以同时将其用于多个视图,因为我们无法在onTouch之外的单个变量中跟踪事件开始时间。
  3. 注意:ViewConfiguration.getLongPressTimeout()是默认值,您可以更改该检查以使用您想要的任何值。

    注意:如果视图通常无法点击,则需要致电view.setClickable(true)以使view.isPressed()检查生效。

    @Override
    public boolean onTouch(View view, MotionEvent event) {
        if (view.isPressed() && event.getAction() == MotionEvent.ACTION_UP) {
            long eventDuration = event.getEventTime() - event.getDownTime();
            if (eventDuration > ViewConfiguration.getLongPressTimeout()) {
                onLongClick(view);
            } else {
                onClick(view);
            }
        }
        return false;
    }
    

    如果您像@ampersandre一样,希望在达到延迟期后立即触发长按事件,而不是等待ACTION_UP,那么以下情况对我来说效果很好。

    @Override
    public boolean onTouch(View view, MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            view.setTag(true);
        } else if (view.isPressed() && (boolean) view.getTag()) {
            long eventDuration = event.getEventTime() - event.getDownTime();
            if (eventDuration > ViewConfiguration.getLongPressTimeout()) {
                view.setTag(false);
                onLongClick(view);
            } else if (event.getAction() == MotionEvent.ACTION_UP) {
                onClick(view);
            }
        }
        return false;
    }
    

答案 3 :(得分:2)

final boolean[] isLongPress = {false};
final int duration = 3000;
final Handler someHandler = new Handler();
    final Runnable someCall = new Runnable() {
        @Override
        public void run() {
            if(isLongPress[0]) {
                // your code goes here 
            }
        }
    };

    someButton.setOnTouchListener(new View.OnTouchListener() {

        @Override
        public boolean onTouch(View v, MotionEvent event) {
            int eventAction = event.getAction();
            if(eventAction == MotionEvent.ACTION_DOWN){
                isLongPress[0] = true;
                someHandler.postDelayed(someCall, duration);
            }
            else if (eventAction == MotionEvent.ACTION_UP) {
                isLongPress[0] = false;
                someHandler.removeCallbacks(someCall);
            }
            return false;
        }
    });

答案 4 :(得分:2)

一种方法可以做到。它易于使用,易于配置时间长度,准时触发回调。

sencha package repo

答案 5 :(得分:1)

我找到了一个研究长按事件如何运作的简单解决方案。 每次单击视图时,Runnable类型CheckForLongPress都会添加到具有延迟的队列中。如果延迟结束,则调用OnLongClickListener。如果在延迟结束之前存在不同的事件,那么CheckForLongPress Runnable将从队列中删除。

我只是覆盖视图的公共方法postDelayed(Runnable action, long delayMillis)以更改操作系统延迟

@Override public boolean postDelayed(Runnable action, long delayMillis) {
    boolean isLongPress = action.getClass().getSimpleName().equals("CheckForLongPress");
    return super.postDelayed(action, isLongPress ? LONG_PRESS_MILLIS : delayMillis);
}

我将LONG_PRESS_MILLIS设置为100并且它正在运行!

希望它有所帮助! ;)

答案 6 :(得分:0)

我找到了这种方法。很简单。

private static final long HOLD_PRESS_TIME = 1200; //ms unit    

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_control);

    //Declare your button and add listener
    ImageView iconImg = findViewById(R.id.more_icon);
    iconImg.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View view, MotionEvent motionEvent) {
            switch (motionEvent.getAction()){
                case MotionEvent.ACTION_DOWN:
                    Log.w("Button", "Button is pressed...");
                    //Start timer
                    timer.start();
                    break;
                case MotionEvent.ACTION_UP:
                    Log.w("Button", "Button is released...");
                    //Clear timer
                    timer.cancel();
                    break;
            }
            return false;
        }
    });


}

private CountDownTimer timer = new CountDownTimer(HOLD_PRESS_TIME, 200) {
    @Override
    public void onTick(long l) {
        Log.w("Button", "Count down..."+l); //It call onFinish() when l = 0
    }

    @Override
    public void onFinish() {
        //TODO your action here!
        Log.w("Button", "Count finish...");

    }
};

答案 7 :(得分:0)

供以后参考,这是我的实现方式:)

public abstract class MyLongClickListener implements View.OnTouchListener {

    private int delay;
    private boolean down;
    private Runnable callback;
    private RectF mRect = new RectF();

    public MyLongClickListener(int delay) {
        this.delay = delay;
        this.callback = new Runnable() {
            @Override
            public void run() {
                down = false;
                onLongClick();
            }
        };
    }

    public abstract void onLongClick();

    @Override
    public boolean onTouch(View v, MotionEvent e) {
        if (e.getPointerCount() > 1) return true;

        int action = e.getAction();
        if (action == MotionEvent.ACTION_DOWN) {
            down = true;
            mRect.set(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
            v.postDelayed(callback, delay);
            return false;

        } else if (action == MotionEvent.ACTION_MOVE) {
            if (down && !mRect.contains(v.getLeft() + e.getX(), v.getTop() + e.getY())) {
                v.removeCallbacks(callback);
                down = false;
                return false;
            }

        } else if (action == MotionEvent.ACTION_UP) {
            if (down) {
                v.removeCallbacks(callback);
                v.performClick();
            }
            return true;

        } else if (action == MotionEvent.ACTION_CANCEL) {
            v.removeCallbacks(callback);
            down = false;
        }

        return false;
    }

}

用法:

textView.setOnTouchListener(new MyLongClickListener(2000) {
    @Override
    public void onLongClick() {
        System.err.println("onLongClick");
    }
});