現在使用しています
onTouchEvent(MotionEvent event){
}
ユーザーが私のglSurfaceViewを押したときを検出するには、長いクリックが行われたときを検出する方法があります。私はdevのドキュメントで多くを見つけることができない場合、それはメソッドの回避策のようなものになるだろうと推測しています。 ACTION_DOWNを登録し、ACTION_UPの前にどれくらいの長さがあるかを確認するようなものです。
Opengl-esを使用してAndroidの長押しをどのように検出しますか?
これを試して:
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);
};
GestureDetectorが最適なソリューションです。
これは興味深い代替案です。 onTouchEvent on ACTION_DOWNで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);
}
クリック、ロングクリック、動きを検出するコードがあります。これは、上記の回答と、すべてのドキュメントページを覗いて行った変更のかなりの組み合わせです。
//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;
}
私は自分のアプリケーションでそれを使用したので、それが機能していることを確認します。
ユーザーが押すことを意味する場合、クリックを意味しますか?クリックとは、ユーザーが押してからすぐに指を離すことです。したがって、2つのonTouchイベントが含まれます。最初のタッチまたはリリース後に発生するイベントのために、onTouchEventの使用を保存する必要があります。
したがって、クリックの場合はonClickListenerを使用する必要があります。
あなたの答えは似ています:onLongClickListenerを使用します。
私は snippet を作成しました-実際のViewソースに触発-カスタム遅延で確実に長いクリック/プレスを検出します。しかし、それはコトリンにあります:
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
}
MSquareによる解決策は、特定のピクセルを保持している場合にのみ機能しますが、マウスを使用しない限り(エンドユーザーは指を使用しない限り)、それはエンドユーザーにとって不合理な期待です。
そのため、間にMOVEアクションがある場合に備えて、DOWNアクションとUPアクションの間の距離に少ししきい値を追加しました。
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);
}
将来的にはロングクリックを実行するためのRunnable
を作成するという考え方ですが、この実行はクリックまたは移動のためにキャンセルできます。
また、長いクリックが消費されたとき、および指が動きすぎてキャンセルされたときを知る必要があります。 initialTouchX
&initialTouchY
を使用して、ユーザーが各辺5ピクセルの10ピクセルの正方形領域を出るかどうかを確認します。
委任の完全なコードを次に示しますClick&LongClick from Cell
in ListView
to Activity
with 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
}
}
}
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;
}
});
ボタンの長押しを検出するための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");
}