子が false を返した場合、親ビューに MotionEvent を想定させる
-
27-10-2019 - |
質問
通常とは異なる方法でイベント処理を必要とするアプリケーションがあります。
私の質問として、まず Android の現在のイベント処理システムが私に合わない簡単なケースを説明しましょう。
FrameLayout (以降 ViewSwiper と呼びます) があり、そこに追加されたすべての View が MATCH_PARENT X MATCH_PARENT (PageView と呼びます) であると仮定すると、実際の View を変換し、方向に基づいて置き換えることによってイベントを処理します。移動の。このコンポーネントはすでに実行済みで、適切に動作します( アニメーションを使用してビューをスワイプする ).
しかし、問題はその上に追加した PageView にあります。onTouchEvent で false を返す ImageView の場合、ViewSwiper がイベントを処理し、別の PageView が画面に入るようになりますが、それに ScrollView を追加すると、すべてのイベントは Scroll によって消費され、ViewSwiper が PageView を置き換える機会はありません。
そこで、ScrollView の onTouchEvent が false を返すと、親はそれがイベントであるとみなせることがわかり、それをテストするために ScrollView の次のサブクラスを作成しました。
public class ScrollViewVertical extends ScrollView {
public ScrollViewVertical(Context context) {
super(context);
setOverScrollMode(OVER_SCROLL_ALWAYS);
setVerticalScrollBarEnabled(false);
}
public boolean onTouchEvent(MotionEvent evt) {
super.onTouchEvent(evt);
return false;
}
}
ただし、 false を返すと、さらにイベントが親にディスパッチされますが、これらのイベントは垂直スクロールに必要なので、ユーザーが水平に移動している場合にのみ false を返すという考えがあります。それが私のコードのようになります。
public class ScrollViewVertical extends ScrollView {
private MovementTracker moveTracker;
public ScrollViewVertical(Context context) {
super(context);
setOverScrollMode(OVER_SCROLL_ALWAYS);
setVerticalScrollBarEnabled(false);
moveTracker = new MovementTracker();
}
public boolean onTouchEvent(MotionEvent evt) {
if (moveTracker.track(evt))
if (moveTracker.getDirection() == Direction.HORIZONTAL)
return false;
return super.onTouchEvent(evt);
}
}
追伸:MovementTracker は、いくつかのイベントの後に track() で true を返し、ユーザーがどの方向に移動しているかを伝えます。
ただし、その場合、ScrollView は最初のイベントで true を返すため、イベントを受信し続けます。
ViewSwiper の子が false を返した場合 (一部の true が返された場合でも)、ViewSwiper でイベントを処理する方法についてのアイデアはありますか。
追伸:必要に応じて、これについてさらに詳しい情報を提供し、別の解決策も受け入れることができます。
回答に基づいて、次のことを試しました。
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
onTouchEvent(ev);
return intercept;
}
public boolean onTouchEvent(MotionEvent evt) {
boolean x = super.onTouchEvent(evt);
if (moveTracker.track(evt)) {
intercept = moveTracker.getDirection() != Direction.VERTICAL;
if (!intercept)
getParent().requestDisallowInterceptTouchEvent(false);
}
return x;
}
まだ何もありません。
解決
これを試してみてください onTouchEvent()
ScrollViewの
//if (evt.getAction() == MotionEvent.ACTION_MOVE) {
if (moveTracker.track(evt)){
if (moveTracker.getDirection() == Direction.VERTICAL){
//Or the direction you want the scrollview keep moving
getParent().requestDisallowInterceptTouchEvent(true);
}
}
return true;
アップデート
Custom ScrollViewに以下を試してください
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
super.dispatchTouchEvent(ev);
return false;
}
何もありません
このようにして、MotionEventが両方のビューで実行されると仮定します。そして、彼らは競合しないので(一方は垂直であるため、もう1つは水平です)これは機能する可能性があります
他のヒント
weakwire からの回答に基づいて、次の解決策にたどり着きました。
ViewSwiper で
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if(!super.dispatchTouchEvent(ev))
onTouchEvent(ev);
return true;
}
そして、Scrollhorizontal では、もう必要ない場合は、dispatchTouchEvent で false を返します。