Androidでは、ユーザーがボタンをタッチしてこのボタンの領域外にドラッグしたかどうかをどのように検出できますか?
MotionEvent.MOVE_OUTSIDEを確認します。 MotionEvent.MOVEを確認します。
private Rect rect; // Variable rect to hold the bounds of the view
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN){
// Construct a rect of the view's bounds
rect = new Rect(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
}
if(event.getAction() == MotionEvent.ACTION_MOVE){
if(!rect.contains(v.getLeft() + (int) event.getX(), v.getTop() + (int) event.getY())){
// User moved outside bounds
}
}
return false;
}
注:Android 4.0、新しい可能性の全世界が開きます: http://developer.Android.com/reference/Android/view/MotionEvent.html #ACTION_HOVER_ENTER
Entrecoによって投稿された答えは、私の場合、若干の微調整が必要でした。私は代用しなければなりませんでした:
_if(!rect.contains((int)event.getX(), (int)event.getY()))
_
for
_if(!rect.contains(v.getLeft() + (int) event.getX(), v.getTop() + (int) event.getY()))
_
event.getX()
とevent.getY()
は、画面全体ではなくImageView自体にのみ適用されるためです。
OnTouchにいくつかのログを追加し、MotionEvent.ACTION_CANCEL
がヒットしていました。それは私にとって十分です...
(1)特定のView
がタッチダウンされたとき、および(2)View
でダウンタッチが解除されたとき、または(3)ダウンタッチがView
の境界の外側に移動したとき。このスレッドにさまざまな答えを集めて_View.OnTouchListener
_(名前はSimpleTouchListener
)の単純な拡張を作成し、他の人がMotionEvent
オブジェクトをいじる必要がないようにしました。クラスのソースは here またはこの回答の下部にあります。
このクラスを使用するには、次のView.setOnTouchListener(View.OnTouchListener)
メソッドの単一のパラメーターとして設定します。
_myView.setOnTouchListener(new SimpleTouchListener() {
@Override
public void onDownTouchAction() {
// do something when the View is touched down
}
@Override
public void onUpTouchAction() {
// do something when the down touch is released on the View
}
@Override
public void onCancelTouchAction() {
// do something when the down touch is canceled
// (e.g. because the down touch moved outside the bounds of the View
}
});
_
プロジェクトに追加できるクラスのソースは次のとおりです。
_public abstract class SimpleTouchListener implements View.OnTouchListener {
/**
* Flag determining whether the down touch has stayed with the bounds of the view.
*/
private boolean touchStayedWithinViewBounds;
@Override
public boolean onTouch(View view, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touchStayedWithinViewBounds = true;
onDownTouchAction();
return true;
case MotionEvent.ACTION_UP:
if (touchStayedWithinViewBounds) {
onUpTouchAction();
}
return true;
case MotionEvent.ACTION_MOVE:
if (touchStayedWithinViewBounds
&& !isMotionEventInsideView(view, event)) {
onCancelTouchAction();
touchStayedWithinViewBounds = false;
}
return true;
case MotionEvent.ACTION_CANCEL:
onCancelTouchAction();
return true;
default:
return false;
}
}
/**
* Method which is called when the {@link View} is touched down.
*/
public abstract void onDownTouchAction();
/**
* Method which is called when the down touch is released on the {@link View}.
*/
public abstract void onUpTouchAction();
/**
* Method which is called when the down touch is canceled,
* e.g. because the down touch moved outside the bounds of the {@link View}.
*/
public abstract void onCancelTouchAction();
/**
* Determines whether the provided {@link MotionEvent} represents a touch event
* that occurred within the bounds of the provided {@link View}.
*
* @param view the {@link View} to which the {@link MotionEvent} has been dispatched.
* @param event the {@link MotionEvent} of interest.
* @return true iff the provided {@link MotionEvent} represents a touch event
* that occurred within the bounds of the provided {@link View}.
*/
private boolean isMotionEventInsideView(View view, MotionEvent event) {
Rect viewRect = new Rect(
view.getLeft(),
view.getTop(),
view.getRight(),
view.getBottom()
);
return viewRect.contains(
view.getLeft() + (int) event.getX(),
view.getTop() + (int) event.getY()
);
}
}
_
ビューがスクロールビュー内にある場合を除き、上位2つの答えは問題ありません。指を動かしたためにスクロールが発生した場合、モーションイベントではなくタッチイベントとして登録されます。答えを改善するには(ビューがスクロール要素内にある場合にのみ必要です):
private Rect rect; // Variable rect to hold the bounds of the view
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN){
// Construct a rect of the view's bounds
rect = new Rect(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
} else if(rect != null && !rect.contains(v.getLeft() + (int) event.getX(), v.getTop() + (int) event.getY())){
// User moved outside bounds
}
return false;
}
私はこれをAndroid 4.3およびAndroid 4.4
Moritzの回答とトップ2の違いに気付いていませんが、これは彼の回答にも当てはまります。
private Rect rect; // Variable rect to hold the bounds of the view
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN){
// Construct a rect of the view's bounds
rect = new Rect(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
} else if (rect != null){
v.getHitRect(rect);
if(rect.contains(
Math.round(v.getX() + event.getX()),
Math.round(v.getY() + event.getY()))) {
// inside
} else {
// outside
}
}
return false;
}
がここにあります View.OnTouchListener
MotionEvent.ACTION_UP
は、ユーザーがビューの外に指を置いているときに送信されました。
private OnTouchListener mOnTouchListener = new View.OnTouchListener() {
private Rect rect;
@Override
public boolean onTouch(View v, MotionEvent event) {
if (v == null) return true;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
rect = new Rect(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
return true;
case MotionEvent.ACTION_UP:
if (rect != null
&& !rect.contains(v.getLeft() + (int) event.getX(),
v.getTop() + (int) event.getY())) {
// The motion event was outside of the view, handle this as a non-click event
return true;
}
// The view was clicked.
// TODO: do stuff
return true;
default:
return true;
}
}
};
@FrostRocketからの回答は正しいですが、view.getX()およびYを使用して、翻訳の変更も考慮する必要があります。
view.getHitRect(viewRect);
if(viewRect.contains(
Math.round(view.getX() + event.getX()),
Math.round(view.getY() + event.getY()))) {
// inside
} else {
// outside
}
view.setClickable(true);
view.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (!v.isPressed()) {
Log.e("onTouch", "Moved outside view!");
}
return false;
}
});
view.isPressed
はview.pointInView
を使用し、タッチスロップが含まれます。スロップが必要ない場合は、内部view.pointInView
(パブリックですが、隠されているため公式APIの一部ではなく、いつでも消える可能性があります)からロジックをコピーするだけです。
view.setClickable(true);
view.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
v.setTag(true);
} else {
boolean pointInView = event.getX() >= 0 && event.getY() >= 0
&& event.getX() < (getRight() - getLeft())
&& event.getY() < (getBottom() - getTop());
boolean eventInView = ((boolean) v.getTag()) && pointInView;
Log.e("onTouch", String.format("Dragging currently in view? %b", pointInView));
Log.e("onTouch", String.format("Dragging always in view? %b", eventInView));
v.setTag(eventInView);
}
return false;
}
});