在我正在处理的应用程序中,我要求用户必须点击&在某个动作发生之前将某个组件保留一段时间。
我目前正在使用OnLongClickListener来监听longclick,但我发现触发OnLongClick事件的点击时间太短。
例如,假设LongClick事件在400ms单击后触发,但我希望用户必须单击&在事件触发前保持1200ms。
有什么方法可以配置LongClick事件以要求更长的点击次数?
或者是否有另一种构造可以让我倾听更长的点击次数?
答案 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)
这是我发现实现此行为的最简单方法。它比目前接受的答案有几个优点。
view.isPressed
,如果触摸事件离开视图,我们会确保不会触发onClick
和onLongClick
。这模仿了系统的默认onClick
和onLongClick
行为。ACTION_DOWN
上存储开始时间或自行计算ACTION_UP
上的当前时间。这意味着我们可以同时将其用于多个视图,因为我们无法在onTouch
之外的单个变量中跟踪事件开始时间。注意: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");
}
});