Android View、View Groupイベント配信


以前にも関連資料を見たことがあり、使ったことも少なくありませんが、覚えておいてください.ViewがDrawableを継承していることを理解してほしいです.Callback, KeyEvent.Callback, AccessibilityEventSource
ViewRootImpl frameworks/base/core/java/android/view/ViewRootImpl.java
View frameworks/base/core/java/android/view/View.java
イベントの転送(最外層のviewから最初に取得)
ViewGroup - ViewGroup - view
Viewでのメソッドイベントの配布
public boolean dispatchTouchEvent(MotionEvent ev)  

イベントブロック(デフォルトはfalseを返します)
public boolean onInterceptTouchEvent(MotionEvent ev)

イベント処理(デフォルトはfalseを返します)
public boolean onTouchEvent(MotionEvent ev)

*デフォルトの配布と処理を組み合わせると、閉ループに似ています*1.1最上位の親ViewのdispatchTouchEventにイベント配布を行います.
true自己処理(onTouchEventに入る)falseアクセス(メソッドonInterceptTouchEvent)イベントをブロックするかどうかを確認ブロックするtrue-(本ViewonTouchEventに入る)ブロックしないでfalseに戻る-(サブViewに送る)
1.2子View同一判断
1.3ビューが自分に子ビューがないことに気づいた場合、自分で処理します.
2 2.1子ViewのonTouchEvent
false(処理を行わない)onTouchEventイベントを返すと親Viewに渡され、親ViewのonTouchEventが戻りtrue(処理を行う)が自身に渡されたonTouchEvent処理を受け入れる
  • ビューがブロックされ、onTouchEvent
  • が処理される
    1.ソースViewがイベントメッセージの1.1 viewをどのように取得するかの初期化
    public class View implements Drawable.Callback, KeyEvent.Callback, AccessibilityEventSource {
    
    //    
     public View(Context context, AttributeSet attrs, int defStyle) {
    
    //
     View() {
            mResources = null;
        }

    1.2 attachInfoの取得
      /** * @param info the {@link android.view.View.AttachInfo} to associated with * this view */
        void dispatchAttachedToWindow(AttachInfo info, int visibility) {
            //System.out.println("Attached! " + this);
            mAttachInfo = info;
            mWindowAttachCount++;
            // We will need to evaluate the drawable state at least once.
            mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY;
            if (mFloatingTreeObserver != null) {
                info.mTreeObserver.merge(mFloatingTreeObserver);
                mFloatingTreeObserver = null;
            }
            if ((mPrivateFlags&PFLAG_SCROLL_CONTAINER) != 0) {
                mAttachInfo.mScrollContainers.add(this);
                mPrivateFlags |= PFLAG_SCROLL_CONTAINER_ADDED;
            }
            performCollectViewAttributes(mAttachInfo, visibility);
            onAttachedToWindow();
    
            ListenerInfo li = mListenerInfo;
            final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners =
                    li != null ? li.mOnAttachStateChangeListeners : null;
            if (listeners != null && listeners.size() > 0) {
                // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to
                // perform the dispatching. The iterator is a safe guard against listeners that
                // could mutate the list by calling the various add/remove methods. This prevents
                // the array from being modified while we iterate it.
                for (OnAttachStateChangeListener listener : listeners) {
                    listener.onViewAttachedToWindow(this);
                }
            }
    
            int vis = info.mWindowVisibility;
            if (vis != GONE) {
                onWindowVisibilityChanged(vis);
            }
            if ((mPrivateFlags&PFLAG_DRAWABLE_STATE_DIRTY) != 0) {
                // If nobody has evaluated the drawable state yet, then do it now.
                refreshDrawableState();
            }
            needGlobalAttributesUpdate(false);
        }

    1.3 View RootImplの取得
        /** * Gets the view root associated with the View. * @return The view root, or null if none. * @hide */
        public ViewRootImpl getViewRootImpl() {
            if (mAttachInfo != null) {
                return mAttachInfo.mViewRootImpl;
            }
            return null;
        }
    

    1.4 ViewのdispatchPointerEvent(これが伝わるポイントです)、dispatchTouchEventを得てMotionEventを得る
      public final boolean dispatchPointerEvent(MotionEvent event) {
            if (event.isTouchEvent()) {
                return dispatchTouchEvent(event);
            } else {
                return dispatchGenericMotionEvent(event);
            }
        }

    1.5次はdispatchTouchEvent、次は他にも伝わります
        public boolean dispatchTouchEvent(MotionEvent event) {
            if (mInputEventConsistencyVerifier != null) {
    //======================================================= mInputEventConsistencyVerifier.onTouchEvent(event, 0);
            }
    
            if (onFilterTouchEventForSecurity(event)) {
                //noinspection SimplifiableIfStatement
                ListenerInfo li = mListenerInfo;
                if (li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED
                        && li.mOnTouchListener.onTouch(this, event)) {
                    return true;
                }
    //=========================================
                if (onTouchEvent(event)) {
                    return true;
                }
            }
    
            if (mInputEventConsistencyVerifier != null) {
                mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);
            }
            return false;
        }