そして、最後にAndroidのビューイベント配信のViewGroupのイベント配信(ソースベースのAndroid3.0)を分析するBenpian
ViewGroupのイベント配布:
あなたは私たちが最初に明確にする必要があります開始する前に、Androidの測定、レイアウト、または層によって子ビューのレイアウト層に親から下降していることすべてを描くのいずれかは、もちろん、イベント配信も例外ではありませんので、すべての時間は、トリガイベントは、画面をタッチしなければなりませんトリガイベントは、最初の親のレイアウトされた後、対応するサブビューの層、マストトリガビューを挙げる各物品上のタッチスクリーンと組み合わせて、この結論dispatchTouchEvent方法を理解して、我々は、対応のViewGroup内を検索しますこの方法、およびこの方法から正確にイベント配布のViewGroup:
/**
* {@inheritDoc}
*/
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (!onFilterTouchEventForSecurity(ev)) {
return false;
}
final int action = ev.getAction();
final float xf = ev.getX();
final float yf = ev.getY();
final float scrolledXFloat = xf + mScrollX;
final float scrolledYFloat = yf + mScrollY;
final Rect frame = mTempRect;
boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
if (action == MotionEvent.ACTION_DOWN) {
if (mMotionTarget != null) {
// this is weird, we got a pen down, but we thought it was
// already down!
// XXX: We should probably send an ACTION_UP to the current
// target.
mMotionTarget = null;
}
// If we're disallowing intercept or if we're allowing and we didn't
// intercept
if (disallowIntercept || !onInterceptTouchEvent(ev)) {
// reset this event's action (just to protect ourselves)
ev.setAction(MotionEvent.ACTION_DOWN);
// We know we want to dispatch the event down, find a child
// who can handle it, start with the front-most child.
final int scrolledXInt = (int) scrolledXFloat;
final int scrolledYInt = (int) scrolledYFloat;
final View[] children = mChildren;
final int count = mChildrenCount;
for (int i = count - 1; i >= 0; i--) {
final View child = children[i];
if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE
|| child.getAnimation() != null) {
child.getHitRect(frame);
if (frame.contains(scrolledXInt, scrolledYInt)) {
// offset the event to the view's coordinate system
final float xc = scrolledXFloat - child.mLeft;
final float yc = scrolledYFloat - child.mTop;
ev.setLocation(xc, yc);
child.mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT;
if (child.dispatchTouchEvent(ev)) {
// Event handled, we have a target now.
mMotionTarget = child;
return true;
}
// The event didn't get handled, try the next view.
// Don't reset the event's location, it's not
// necessary here.
}
}
}
}
}
boolean isUpOrCancel = (action == MotionEvent.ACTION_UP) ||
(action == MotionEvent.ACTION_CANCEL);
if (isUpOrCancel) {
// Note, we've already copied the previous state to our local
// variable, so this takes effect on the next event
mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
}
// The event wasn't an ACTION_DOWN, dispatch it to our target if
// we have one.
final View target = mMotionTarget;
if (target == null) {
// We don't have a target, this means we're handling the
// event as a regular view.
ev.setLocation(xf, yf);
if ((mPrivateFlags & CANCEL_NEXT_UP_EVENT) != 0) {
ev.setAction(MotionEvent.ACTION_CANCEL);
mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT;
}
return super.dispatchTouchEvent(ev);
}
// if have a target, see if we're allowed to and want to intercept its
// events
if (!disallowIntercept && onInterceptTouchEvent(ev)) {
final float xc = scrolledXFloat - (float) target.mLeft;
final float yc = scrolledYFloat - (float) target.mTop;
mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT;
ev.setAction(MotionEvent.ACTION_CANCEL);
ev.setLocation(xc, yc);
if (!target.dispatchTouchEvent(ev)) {
// target didn't handle ACTION_CANCEL. not much we can do
// but they should have.
}
// clear the target
mMotionTarget = null;
// Don't dispatch this event to our own view, because we already
// saw it when intercepting; we just want to give the following
// event to the normal onTouchEvent().
return true;
}
if (isUpOrCancel) {
mMotionTarget = null;
}
// finally offset the event to the target's coordinate system and
// dispatch the event.
final float xc = scrolledXFloat - (float) target.mLeft;
final float yc = scrolledYFloat - (float) target.mTop;
ev.setLocation(xc, yc);
if ((target.mPrivateFlags & CANCEL_NEXT_UP_EVENT) != 0) {
ev.setAction(MotionEvent.ACTION_CANCEL);
target.mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT;
mMotionTarget = null;
}
return target.dispatchTouchEvent(ev);
}
たくさんの長いにおけるdispatchTouchEvent方法に関してのViewGroupビュー、我々は、フォーカスを見て選びます。!OnInterceptTouchEvent(EV)ダウンdisallowIntercept ||後の裁判官は、コメントが無効になって無効になっているかいない傍受することによって見ることができますが、イベントをインターセプトする必要がない場合に発生するアクションを決定する際にあれば内部の判断、内部のViewGroupの判断を入力しますサブビューが横断されるすべてのサブビューが子ならば(で、子ビューのクリックを得るために)子の観点から、現在のヒット領域は、その後、もしdispatchTouchEventの(child.dispatchTouchEvent(EV))()メソッドを介して呼び出すかどうかを判断しますdispatchTouchEventの真のビューを返す()メソッドは、サブビュー及び真dispatchTouchEvent真、すなわち、サブビューイベント処理とリターンのmMotionTargetのViewGroup方法入射と、親ビューなくなり取引に割り当てられます。
そしてmMotionTargetが割り当てられていないか、またはdivpatchTouchEventのサブビューがfalseを返し、それは下向き継続する、我々はmMotionTargetがnullの場合の呼び出しがsuper.dispatchTouchEvent(EV)を返した後ことがわかりサブビューを横断した後にクリックされていない場合dispatchTouchEventのViewGroup方法はので、ここでビューから継承しながら、事件を処理するビューと呼ばれています。
また、ここで||判断の二つの基準値について説明するdisallowIntercept onInterceptTouchEvent(EV)用:! DisallowInterceptスワップイベント傍受機能を無効にするかどうかを意味し、デフォルトはfalseで、あなたもrequestDisallowInterceptTouchEventメソッドを呼び出すことで、この値を変更することができます。!OnInterceptTouchEvent(EV)はonInterceptTouchEvent否定の戻り値です!我々は偽onInterceptTouchEventメソッドを返す場合、第二はそう、我々は真のonInterceptTouchEventメソッドを返す場合は、2番目が偽であることを確認します、裁きの内部の状態に入ること、真実であることを確認することが、この手段この条件のうち。
これまでのViewGroupイベントが終わりに配布するために、我々は次のような結論を知ることができます。
- 1.Androidイベント配布は父親から息子にあります
- それがfalseを返した場合、イベントは、子ビューに対処するために自分自身を通過していない場合2.真onInterceptTouchEventイベントインターセプタメソッドが返すことでのViewGroupにすることができ、イベントはデフォルトのメソッドが返す偽の、子ビューに送信されます。
- 3.イベントをサブビューによって処理されている場合は、親ビューには、すべてのイベントを受信しません。
ビュー・グループのイベントは、コールグラフを分散します:
参考文献: