안 드 로 이 드 의 이벤트 배포 메커니즘 에 대해 이야기 하 다.

View 사건 배포 체제 의 본질은 바로 MotionEvent 사건 의 배포 과정,즉 MotionEvent 가 발생 한 후에 View 간 에 어떻게 전달 하고 처리 하 는 지 하 는 것 이다.
먼저 모 션 이벤트 가 무엇 인지 소개 합 니 다.모 션 이벤트 란 사용자 가 손가락 으로 휴대 전화 화면 을 만 질 때 발생 하 는 일련의 터치 사건 입 니 다.전형 적 인 터치 사건 은 다음 과 같다.
  • ACTION_DOWN:손가락 이 화면 에 닿 는 순간..
  • ACTION_MOVE:손가락 이 화면 에서 미 끄 러 집 니 다
  • ACTION_UP:손가락 이 화면 을 떠 나 는 순간..
  • ACTION_CANCLE:현재 이벤트 시퀀스 가 종 료 됩 니 다.
  • 하나의 이벤트 시퀀스 는 일반적으로 다운 이벤트 로 시작 하고 UP 이벤트 가 종료 되 며 중간 에 여러 개의 MOVE 이벤트 가 삽입 된다.
    사건 의 전달 순서:Activity(Window)→ViewGroup→View,즉 사건 은 Activity 에서 아래로 전달 된다.
    사건 의 배포 와 관련 된 세 가지 주요 방법:
    dispatchTouchEvent:위 에서 아래로 사건 을 전달 합 니 다.그 반환 값 은 하위 View 의 dispatchTouchEvent 방법 과 현재 View 의 onTouchEvent 방법 에 영향 을 받 습 니 다
  • onInterceptTouchEvent:사건 을 차단 합 니 다.이 방법 은 View Group 만 의 것 입 니 다.이벤트 시퀀스 의 특정한 사건 을 차단 하면 이 시퀀스 의 나머지 사건 은 차단 한 ViewGroup 에 맡 기 고 이 방법 을 다시 사용 하지 않 습 니 다
  • onTouchEvent:특정한 사건 을 소모 하면 특정한 사건 을 처리 합 니 다
  • 이 어 액 티 비 티,뷰 그룹,뷰 의 이벤트 배포 메커니즘 에 대해 설명 한다.
    Activity 의 이벤트 배포 메커니즘
    클릭 이벤트 가 발생 했 을 때 이 이 벤트 는 Activity 의 dispatchTouchEvent()방법 으로 가장 먼저 전 달 됩 니 다.
    Activity 는 dispatchTouchEvent()방법 에서 getWindow().superDispatchTouchEvent()방법 을 호출 하여 이 벤트 를 Window 의 mDecor(DecorView)에 전달 하고 mDecor 는 superDispatchTouchEvent 방법 을 호출 하여 이 벤트 를 ViewGroup 에 전달 합 니 다.
    
    /**
      *     :Activity.dispatchTouchEvent()
      */ 
        public boolean dispatchTouchEvent(MotionEvent ev) {
        
                if (ev.getAction() == MotionEvent.ACTION_DOWN) {
                    onUserInteraction();
                }
    
                if (getWindow().superDispatchTouchEvent(ev)) {
    
                    return true;
                    //  getWindow().superDispatchTouchEvent(ev)   true
                    //  Activity.dispatchTouchEvent()   true,     。  :            &         
                    //   :      Activity.onTouchEvent
    
                }
                return onTouchEvent(ev);
            }
    
    /**
      * getWindow().superDispatchTouchEvent(ev)
      *   :
      *     a. getWindow() =   Window    
      *     b. Window     ,       = PhoneWindow ;    Window    = PhoneWindow   
      *     c. Window  superDispatchTouchEvent() = 1     ,   PhoneWindow   
      */
        @Override
        public boolean superDispatchTouchEvent(MotionEvent event) {
    
            return mDecor.superDispatchTouchEvent(event);
            // mDecor =   View(DecorView)     
        }
    
    /**
      * mDecor.superDispatchTouchEvent(event)
      *   :    View(DecorView)
      *   :
      *     a. DecorView  PhoneWindow       
      *     b. DecorView   FrameLayout,        
      *     c. FrameLayout ViewGroup   , DecorView      = ViewGroup
      */
        public boolean superDispatchTouchEvent(MotionEvent event) {
    
            return super.dispatchTouchEvent(event);
            //         = ViewGroup dispatchTouchEvent()
            //         ViewGroup   ,    ViewGroup       
    
        }
    
    /**
      * Activity.onTouchEvent()
      *   :    View(DecorView)
      *   :
      *     a. DecorView  PhoneWindow       
      *     b. DecorView   FrameLayout,        
      *     c. FrameLayout ViewGroup   , DecorView      = ViewGroup
      */
      public boolean onTouchEvent(MotionEvent event) {
    
            //          Activity     View   /    
            //     :     Window        
            if (mWindow.shouldCloseOnTouch(this, event)) {
                finish();
                return true;
            }
            
            return false;
            //          Window       true,       false
        }
    ViewGroup 의 이벤트 배포 메커니즘
    이벤트 가 Activity 에서 ViewGroup 의 dispatchTouchEvent()로 전 달 된 후 ViewGroup 은 먼저 onInterceptTouchEvent()방법 으로 이 사건 을 차단 할 지 여 부 를 판단 합 니 다.(기본적으로 차단 하지 않 고 차단 하려 면 사용자 가 다시 써 야 합 니 다)이 사건 을 차단 하지 않 으 면 ViewGroup 은 모든 하위 View 를 순환 적 으로 옮 겨 다 니 며 현재 이벤트 가 발생 한 View 를 찾 습 니 다.그리고 이 하위 View 의 dispatchTouchEvent()방법 을 호출 하여 이 벤트 를 하위 View 에 나 누 어 처리 합 니 다.
    이 이벤트 가 ViewGroup 에 의 해 차단 되 거나 이벤트 가 발생 한 View(이벤트 가 빈 곳 에서 발생 함)를 찾 지 못 하면 ViewGroup 은 onTouchEvent()방법 으로 이 벤트 를 처리 합 니 다.
    
    /**
      *     :ViewGroup.dispatchTouchEvent()
      */ 
        public boolean dispatchTouchEvent(MotionEvent ev) { 
    
        ... //        
    
            // ViewGroup       ,    onInterceptTouchEvent()        
                if (disallowIntercept || !onInterceptTouchEvent(ev)) {  
    
                //    1:disallowIntercept =            (   false),     requestDisallowInterceptTouchEvent()  
                //    2: !onInterceptTouchEvent(ev) =  onInterceptTouchEvent()     
                        // a.   onInterceptTouchEvent()   false(      ),        true,            
                        // b.   onInterceptTouchEvent()   true(     ),        false,           
                        // c.   onInterceptTouchEvent() ->>  1
    
                    ev.setAction(MotionEvent.ACTION_DOWN);  
                    final int scrolledXInt = (int) scrolledXFloat;  
                    final int scrolledYInt = (int) scrolledYFloat;  
                    final View[] children = mChildren;  
                    final int count = mChildrenCount;  
    
                //   for  ,     ViewGroup     View
                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);  
    
                        //        View        View,          View
                        //   ,         
                        if (frame.contains(scrolledXInt, scrolledYInt)) {  
                            final float xc = scrolledXFloat - child.mLeft;  
                            final float yc = scrolledYFloat - child.mTop;  
                            ev.setLocation(xc, yc);  
                            child.mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT;  
    
                            //            View dispatchTouchEvent()
                            //           ViewGroup  View   (       View      )
                            if (child.dispatchTouchEvent(ev))  { 
    
                            mMotionTarget = child;  
                            return true; 
                            //    View dispatchTouchEvent       
                            //        ,     ,dispatchTouchEvent       true,           
                            //    ViewGroup dispatchTouchEvent()     true,     
                            //   ViewGroup        
    
                                    }  
                                }  
                            }  
                        }  
                    }  
                }  
                boolean isUpOrCancel = (action == MotionEvent.ACTION_UP) ||  
                        (action == MotionEvent.ACTION_CANCEL);  
                if (isUpOrCancel) {  
                    mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;  
                }  
                final View target = mMotionTarget;  
    
          
            //         (    View    ) /     (    onInterceptTouchEvent(),      true)
            if (target == null) {  
                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);
                //   ViewGroup   dispatchTouchEvent(), View.dispatchTouchEvent()
                //      ViewGroup onTouch() ->> onTouchEvent() ->> performClick() ->> onClick(),        ,        (     View         View.dispatchTouchEvent())
                //         : View dispatchTouchEvent()
            } 
    
            ... 
    
    }
    /**
      * ViewGroup.onInterceptTouchEvent()
      *   :      
      *   :
      *     a.   true =   ,         (     ,   onInterceptTouchEvent(),      true)
      *     b.   false =    (  )
      */
      public boolean onInterceptTouchEvent(MotionEvent ev) {  
        
        return false;
    
      } 
    View 의 이벤트 배포 메커니즘
    이벤트 가 ViewGroup 에서 View 의 dispatchTouchEvent()로 전 달 된 후에 가장 먼저 실행 되 는 것 은 View 의 onTouch()방법 이다.onTouch()방법 은 View 의 OnTouch Listener 인터페이스 에서 정 의 된 방법 입 니 다.사용자 가 View 에 감청 을 등록 하면 사용자 가 화면 을 만 질 때 이 방법 을 실행 합 니 다.이 방법 은 기본적으로 false 로 돌아 갑 니 다.사용자 가 다시 써 야 합 니 다.
    onTouch()방법 이 false 로 되 돌아 와 야 View 의 onTouch Event()방법 을 실행 할 수 있 습 니 다.그리고 상황 에 따라 performClick()방법 을 호출 하고 performClick()방법 에 따라 onClick()방법 을 호출 합 니 다.
    
    /**
      *     :View.dispatchTouchEvent()
      */
      public boolean dispatchTouchEvent(MotionEvent event) {  
    
            if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED &&  
                    mOnTouchListener.onTouch(this, event)) {  
                return true;  
            } 
            return onTouchEvent(event);  
      }
      //   :    3      ,dispatchTouchEvent()   true;    onTouchEvent()
      //     1. mOnTouchListener != null
      //     2. (mViewFlags & ENABLED_MASK) == ENABLED
      //     3. mOnTouchListener.onTouch(this, event)
      //     3       
    
    
    /**
      *   1:mOnTouchListener != null
      *   :mOnTouchListener   View.setOnTouchListener()     
      */
      public void setOnTouchListener(OnTouchListener l) { 
    
        mOnTouchListener = l;  
        //            Touch  ,mOnTouchListener      (   )
            
    } 
    
    /**
      *   2:(mViewFlags & ENABLED_MASK) == ENABLED
      *   :
      *     a.                enable
      *     b.     View  enable,       true
      */
    
    /**
      *   3:mOnTouchListener.onTouch(this, event)
      *   :        Touch    onTouch();       ,    (   Button  )
      */
        button.setOnTouchListener(new OnTouchListener() {  
            @Override  
            public boolean onTouch(View v, MotionEvent event) {  
         
                return false;  
            }  
        });
        //   onTouch()  true,             ,    View.dispatchTouchEvent()    true,      
        //   onTouch()  false,               ,    View.dispatchTouchEvent()   If,  onTouchEvent(event)
    View 의 onTouch Event()가 true 로 돌아 가면 이 사건 을 소모 하면 사건 의 배 포 는 여기 서 끝 납 니 다.false 로 돌아 가면 아래 에서 위로 View Group 과 Activity 의 onTouchEvent()방법 으로 사건 을 처리 합 니 다.특히 Activity 의 onTouch Event()방법 은 사건 을 처리 해 야 한다.
    이로써 사건 의 배 포 는 끝났다.
    이상 은 안 드 로 이 드 의 이벤트 배포 체제 에 대한 상세 한 내용 입 니 다.안 드 로 이 드 이벤트 배포 체제 에 관 한 자 료 는 저희 의 다른 관련 글 을 주목 하 세 요!

    좋은 웹페이지 즐겨찾기