我目前正在使用
onTouchEvent(MotionEvent event){
}
检测用户何时按下我的glSurfaceView是否有办法检测何时进行长按。我猜我是否在开发文档中找不到多少,那么它将是某种方法的工作。类似于注册ACTION_DOWN并查看ACTION_UP之前的时间。
如何使用opengl-es检测Android上的长按?
答案 0 :(得分:145)
GestureDetector 是最佳解决方案。
这是一个有趣的选择。在每个 ACTION_DOWN 上的 onTouchEvent 中安排Runnable在1秒内运行。在每个 ACTION_UP 或 ACTION_MOVE 上,取消预定的Runnable。如果从 ACTION_DOWN 事件中取消的次数少于1秒,则Runnable将无法运行。
final Handler handler = new Handler();
Runnable mLongPressed = new Runnable() {
public void run() {
Log.i("", "Long press!");
}
};
@Override
public boolean onTouchEvent(MotionEvent event, MapView mapView){
if(event.getAction() == MotionEvent.ACTION_DOWN)
handler.postDelayed(mLongPressed, ViewConfiguration.getLongPressTimeout());
if((event.getAction() == MotionEvent.ACTION_MOVE)||(event.getAction() == MotionEvent.ACTION_UP))
handler.removeCallbacks(mLongPressed);
return super.onTouchEvent(event, mapView);
}
答案 1 :(得分:101)
试试这个:
final GestureDetector gestureDetector = new GestureDetector(new GestureDetector.SimpleOnGestureListener() {
public void onLongPress(MotionEvent e) {
Log.e("", "Longpress detected");
}
});
public boolean onTouchEvent(MotionEvent event) {
return gestureDetector.onTouchEvent(event);
};
答案 2 :(得分:5)
我有一个代码可以检测到点击,长按和移动。 它完全是上面给出的答案和我偷窥每个文档页面所做的更改的组合。
//Declare this flag globally
boolean goneFlag = false;
//Put this into the class
final Handler handler = new Handler();
Runnable mLongPressed = new Runnable() {
public void run() {
goneFlag = true;
//Code for long click
}
};
//onTouch code
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
handler.postDelayed(mLongPressed, 1000);
//This is where my code for movement is initialized to get original location.
break;
case MotionEvent.ACTION_UP:
handler.removeCallbacks(mLongPressed);
if(Math.abs(event.getRawX() - initialTouchX) <= 2 && !goneFlag) {
//Code for single click
return false;
}
break;
case MotionEvent.ACTION_MOVE:
handler.removeCallbacks(mLongPressed);
//Code for movement here. This may include using a window manager to update the view
break;
}
return true;
}
我确认它在我自己的应用程序中使用它。
答案 3 :(得分:3)
当您的意思是用户按下时,您的意思是点击吗?点击是指用户按下然后立即抬起手指。因此它包含两个onTouch事件。你应该保存onTouchEvent用于初始触摸或发布后发生的事情。
因此,如果是单击,则应该使用onClickListener。
您的回答类似:使用onLongClickListener。
答案 4 :(得分:1)
MSquare的解决方案只有在您拥有特定像素时才有效,但这对最终用户来说是不合理的期望,除非他们使用鼠标(他们不会使用鼠标)。
所以我为DOWN和UP动作之间的距离添加了一点阈值,以防中间有MOVE动作。
final Handler longPressHandler = new Handler();
Runnable longPressedRunnable = new Runnable() {
public void run() {
Log.e(TAG, "Long press detected in long press Handler!");
isLongPressHandlerActivated = true;
}
};
private boolean isLongPressHandlerActivated = false;
private boolean isActionMoveEventStored = false;
private float lastActionMoveEventBeforeUpX;
private float lastActionMoveEventBeforeUpY;
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN) {
longPressHandler.postDelayed(longPressedRunnable, 1000);
}
if(event.getAction() == MotionEvent.ACTION_MOVE || event.getAction() == MotionEvent.ACTION_HOVER_MOVE) {
if(!isActionMoveEventStored) {
isActionMoveEventStored = true;
lastActionMoveEventBeforeUpX = event.getX();
lastActionMoveEventBeforeUpY = event.getY();
} else {
float currentX = event.getX();
float currentY = event.getY();
float firstX = lastActionMoveEventBeforeUpX;
float firstY = lastActionMoveEventBeforeUpY;
double distance = Math.sqrt(
(currentY - firstY) * (currentY - firstY) + ((currentX - firstX) * (currentX - firstX)));
if(distance > 20) {
longPressHandler.removeCallbacks(longPressedRunnable);
}
}
}
if(event.getAction() == MotionEvent.ACTION_UP) {
isActionMoveEventStored = false;
longPressHandler.removeCallbacks(longPressedRunnable);
if(isLongPressHandlerActivated) {
Log.d(TAG, "Long Press detected; halting propagation of motion event");
isLongPressHandlerActivated = false;
return false;
}
}
return super.dispatchTouchEvent(event);
}
答案 5 :(得分:1)
我创建了一个snippet - 受到实际视图源的启发 - 可以通过自定义延迟可靠地检测长按/按下。但它在Kotlin:
val LONG_PRESS_DELAY = 500
val handler = Handler()
var boundaries: Rect? = null
var onTap = Runnable {
handler.postDelayed(onLongPress, LONG_PRESS_DELAY - ViewConfiguration.getTapTimeout().toLong())
}
var onLongPress = Runnable {
// Long Press
}
override fun onTouch(view: View, event: MotionEvent): Boolean {
when (event.action) {
MotionEvent.ACTION_DOWN -> {
boundaries = Rect(view.left, view.top, view.right, view.bottom)
handler.postDelayed(onTap, ViewConfiguration.getTapTimeout().toLong())
}
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
handler.removeCallbacks(onLongPress)
handler.removeCallbacks(onTap)
}
MotionEvent.ACTION_MOVE -> {
if (!boundaries!!.contains(view.left + event.x.toInt(), view.top + event.y.toInt())) {
handler.removeCallbacks(onLongPress)
handler.removeCallbacks(onTap)
}
}
}
return true
}
答案 6 :(得分:1)
这个想法是为将来执行长按一次创建Runnable
,但是由于点击或移动,可以取消此执行。
您还需要知道,当长时间点击消耗时,以及因为手指移动太多而取消时。我们使用initialTouchX
&amp; initialTouchY
用于检查用户是否退出10像素的正方形区域,每边5个。
以下是我的委托 Click&amp; amp;的完整代码从Cell
ListView
Activity
OnTouchListener
ClickDelegate delegate;
boolean goneFlag = false;
float initialTouchX;
float initialTouchY;
final Handler handler = new Handler();
Runnable mLongPressed = new Runnable() {
public void run() {
Log.i("TOUCH_EVENT", "Long press!");
if (delegate != null) {
goneFlag = delegate.onItemLongClick(index);
} else {
goneFlag = true;
}
}
};
@OnTouch({R.id.layout})
public boolean onTouch (View view, MotionEvent motionEvent) {
switch (motionEvent.getAction()) {
case MotionEvent.ACTION_DOWN:
handler.postDelayed(mLongPressed, ViewConfiguration.getLongPressTimeout());
initialTouchX = motionEvent.getRawX();
initialTouchY = motionEvent.getRawY();
return true;
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_CANCEL:
if (Math.abs(motionEvent.getRawX() - initialTouchX) > 5 || Math.abs(motionEvent.getRawY() - initialTouchY) > 5) {
handler.removeCallbacks(mLongPressed);
return true;
}
return false;
case MotionEvent.ACTION_UP:
handler.removeCallbacks(mLongPressed);
if (goneFlag || Math.abs(motionEvent.getRawX() - initialTouchX) > 5 || Math.abs(motionEvent.getRawY() - initialTouchY) > 5) {
goneFlag = false;
return true;
}
break;
}
Log.i("TOUCH_EVENT", "Short press!");
if (delegate != null) {
if (delegate.onItemClick(index)) {
return false;
}
}
return false;
}
点击:
ClickDelegate
interface
是Activity
,用于将点击事件发送到处理程序类,如 public interface ClickDelegate {
boolean onItemClick(int position);
boolean onItemLongClick(int position);
}
Activity
如果您需要委派行为,那么您需要的是在View
或父public class MyActivity extends Activity implements ClickDelegate {
//code...
//in some place of you code like onCreate,
//you need to set the delegate like this:
SomeArrayAdapter.delegate = this;
//or:
SomeViewHolder.delegate = this;
//or:
SomeCustomView.delegate = this;
@Override
public boolean onItemClick(int position) {
Object obj = list.get(position);
if (obj) {
return true; //if you handle click
} else {
return false; //if not, it could be another event
}
}
@Override
public boolean onItemLongClick(int position) {
Object obj = list.get(position);
if (obj) {
return true; //if you handle long click
} else {
return false; //if not, it's a click
}
}
}
中实施它:
log_level_per_component:
type: object
example:
{
"Component1": "Info",
"Component2": "Debug",
"Component3": "Fatal"
}
答案 7 :(得分:0)
setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
int action = MotionEventCompat.getActionMasked(event);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
longClick = false;
x1 = event.getX();
break;
case MotionEvent.ACTION_MOVE:
if (event.getEventTime() - event.getDownTime() > 500 && Math.abs(event.getX() - x1) < MIN_DISTANCE) {
longClick = true;
}
break;
case MotionEvent.ACTION_UP:
if (longClick) {
Toast.makeText(activity, "Long preess", Toast.LENGTH_SHORT).show();
}
}
return true;
}
});
答案 8 :(得分:0)
这是一种基于MSquare的检测长按按钮的好主意的方法,它具有一个附加功能:不仅响应长按执行操作,而且还会重复操作,直到MotionEvent。收到ACTION_UP消息。在这种情况下,长按和短按动作相同,但是可以不同。
请注意,正如其他人所报告的那样,由于对MotionEvent.ACTION_MOVE消息的响应而删除了回调,因为我无法保持足够的静止感,从而阻止了回调的执行。我通过忽略该消息来解决该问题。
private void setIncrementButton() {
final Button btn = (Button) findViewById(R.id.btn);
final Runnable repeater = new Runnable() {
@Override
public void run() {
increment();
final int milliseconds = 100;
btn.postDelayed(this, milliseconds);
}
};
btn.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent e) {
if (e.getAction() == MotionEvent.ACTION_DOWN) {
increment();
v.postDelayed(repeater, ViewConfiguration.getLongPressTimeout());
} else if (e.getAction() == MotionEvent.ACTION_UP) {
v.removeCallbacks(repeater);
}
return true;
}
});
}
private void increment() {
Log.v("Long Press Example", "TODO: implement increment operation");
}
答案 9 :(得分:0)
我找到了一个解决方案,它不需要定义可运行的东西或其他东西,并且工作正常。
var lastTouchTime: Long = 0
// ( ViewConfiguration.#.DEFAULT_LONG_PRESS_TIMEOUT =500)
val longPressTime = 500
var lastTouchX = 0f
var lastTouchY = 0f
view.setOnTouchListener { v, event ->
when (event.action) {
MotionEvent.ACTION_DOWN -> {
lastTouchTime = SystemClock.elapsedRealtime()
lastTouchX = event.x
lastTouchY = event.y
return@setOnTouchListener true
}
MotionEvent.ACTION_UP -> {
if (SystemClock.elapsedRealtime() - lastTouchTime > longPressTime
&& Math.abs(event.x - lastTouchX) < 3
&& Math.abs(event.y - lastTouchY) < 3) {
Log.d(TAG, "Long press")
}
return@setOnTouchListener true
}
else -> {
return@setOnTouchListener false
}
}
}
答案 10 :(得分:0)
选项:自定义检测器class
abstract public class
Long_hold
extends View.OnTouchListener
{
public@Override boolean
onTouch(View view, MotionEvent touch)
{
switch(touch.getAction())
{
case ACTION_DOWN: down(touch); return true;
case ACTION_MOVE: move(touch);
}
return true;
}
private long
time_0;
private float
x_0, y_0;
private void
down(MotionEvent touch)
{
time_0= touch.getEventTime();
x_0= touch.getX();
y_0= touch.getY();
}
private void
move(MotionEvent touch)
{
if(held_too_short(touch) {return;}
if(moved_too_much(touch)) {return;}
long_press(touch);
}
abstract protected void
long_hold(MotionEvent touch);
}
使用
private double
moved_too_much(MotionEvent touch)
{
return Math.hypot(
x_0 -touch.getX(),
y_0 -touch.getY()) >TOLERANCE;
}
private double
held_too_short(MotionEvent touch)
{
return touch.getEventTime()-time_0 <DOWN_PERIOD;
}
其中
TOLERANCE
是最大容许运动
DOWN_PERIOD
是必须按下的时间
import
static android.view.MotionEvent.ACTION_MOVE;
static android.view.MotionEvent.ACTION_DOWN;
用代码
setOnTouchListener(new Long_hold()
{
protected@Override boolean
long_hold(MotionEvent touch)
{
/*your code on long hold*/
}
});