View의 이벤트 전달 메커니즘 인스턴스 프레젠테이션

12382 단어
본고는 구체적인 예를 통해 지난 글의View 이벤트 전달 메커니즘의 원본 코드 해석에서의 결론을 하나하나 검증했다.이 두 문장을 결합하면 View의 사건 전달 메커니즘은 매우 명확하게 이해되었다.
먼저 MyLinearLayout과 MyButton을 정의하고 몇 가지 관건적인 방법을 다시 씁니다. 코드는 다음과 같습니다. MyLinearLayout:
public class MyLinearLayout extends LinearLayout implements OnTouchListener,OnClickListener{
    public MyLinearLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.setOnTouchListener(this);
        this.setOnClickListener(this);
        // TODO Auto-generated constructor stub
    }
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        // TODO Auto-generated method stub
        switch (ev.getAction()) {
        case MotionEvent.ACTION_DOWN:
            Log.d("Event", "MyLinearLayout----> dispatchTouchEvent, Action_DOWN" );
            break;

        case MotionEvent.ACTION_UP:
            Log.d("Event", "MyLinearLayout----> dispatchTouchEvent, Action_UP" );
            break;
        case MotionEvent.ACTION_MOVE:
            Log.d("Event", "MyLinearLayout----> dispatchTouchEvent, Action_Move" );
            break;
        case MotionEvent.ACTION_CANCEL:
            Log.d("Event", "MyLinearLayout----> dispatchTouchEvent, Action_Cancel" );
            break;
        }
        boolean result = super.dispatchTouchEvent(ev);
        Log.d("Event", "MyLinearLayout---->dispatchTouchEvent: return value is " + result);
        return result;
    }
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        // TODO Auto-generated method stub
    switch (ev.getAction()) {
        
        case MotionEvent.ACTION_DOWN:
            Log.d("Event", "MyLinearLayout----> onInterceptTouchEvent, Action_DOWN" );
            break;
        case MotionEvent.ACTION_UP:
            Log.d("Event", "MyLinearLayout----> onInterceptTouchEvent, Action_UP" );
            break;
        case MotionEvent.ACTION_MOVE:
            Log.d("Event", "MyLinearLayout----> onInterceptTouchEvent, Action_Move" );
            break;
        case MotionEvent.ACTION_CANCEL:
            Log.d("Event", "MyLinearLayout----> onInterceptTouchEvent, Action_Cancel" );
            break;
        }
        return false;
    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // TODO Auto-generated method stub
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            Log.d("Event", "MyLinearLayout----> onTouchEvent, Action_DOWN" );
            break;
        case MotionEvent.ACTION_UP:
            Log.d("Event", "MyLinearLayout----> onTouchEvent, Action_UP" );
            break;
        case MotionEvent.ACTION_MOVE:
            Log.d("Event", "MyLinearLayout----> onTouchEvent, Action_Move" );
            break;
        case MotionEvent.ACTION_CANCEL:
            Log.d("Event", "MyLinearLayout----> onTouchEvent, Action_Cancel" );
            break;
        }
    boolean result =super.onTouchEvent(event);
        Log.d("Event", "MyLinearLayout---->onTouchEvent: return value is " +result );
        return result;
    }
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            Log.d("Event", "MyLinearLayout----> onTouch, Action_DOWN" );
            break;
        case MotionEvent.ACTION_UP:
            Log.d("Event", "MyLinearLayout----> onTouch, Action_UP" );
            break;
        case MotionEvent.ACTION_MOVE:
            Log.d("Event", "MyLinearLayout----> onTouch, Action_Move" );
            break;
        case MotionEvent.ACTION_CANCEL:
            Log.d("Event", "MyLinearLayout----> onTouch, Action_Cancel" );
            break;
        }
        return true;
    }
    @Override
    public void onClick(View v) {
            Log.d("Event", "MyLinearLayout----> onClick, " );
    }
}

MyButton:
public class MyButton extends Button{

    public MyButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        // TODO Auto-generated constructor stub
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        // TODO Auto-generated method stub
        switch (event.getAction()) {
    
        case MotionEvent.ACTION_DOWN:
            Log.d("Event", "MyButton-----> dispatchTouchEvent, Action_DOWN" );
            break;

        case MotionEvent.ACTION_UP:
            Log.d("Event", "MyButton-----> dispatchTouchEvent, Action_UP" );
            break;
        case MotionEvent.ACTION_MOVE:
            Log.d("Event", "MyButton-----> dispatchTouchEvent, Action_Move" );
            break;
        case MotionEvent.ACTION_CANCEL:
            Log.d("Event", "MyButton-----> dispatchTouchEvent, Action_Cancel" );
            break;
        }
        boolean result = super.dispatchTouchEvent(event);
        //Log.d("Event", "MyButton----->dispatchTouchEvent: return value is " + result);
        return result;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // TODO Auto-generated method stub
        
        switch (event.getAction()) {
        
        case MotionEvent.ACTION_DOWN:
            Log.d("Event", "MyButton-----> onTouchEvent, Action_DOWN" );
            break;

        case MotionEvent.ACTION_UP:
            Log.d("Event", "MyButton-----> onTouchEvent, Action_UP" );
            break;
        case MotionEvent.ACTION_MOVE:
            Log.d("Event", "MyButton-----> onTouchEvent, Action_Move" );
            break;
        case MotionEvent.ACTION_CANCEL:
            Log.d("Event", "MyButton-----> onTouchEvent, Action_Cancel" );
            break;
        }
        
        boolean result = super.onTouchEvent(event);
        Log.d("Event", "MyButton----->onTouchEvent: return value is " +result );
        return result;
    }

}

코드는 여러 가지 이벤트와 방법의 이름을 인쇄한 것이 분명하다.유일하게 특이한 것은 Layout에도 온터치와 온클릭 감청이 이뤄졌다는 점이다.그리고 Activity에서 Button의 온터치와 온클릭을 실현하고 Activity의 온터치 이벤트 방법을 계승한다.
public class ViewActivity extends Activity implements OnClickListener,OnTouchListener{
      protected void onCreate(Bundle savedInstanceState) {
           super.onCreate(savedInstanceState);
           setContentView(R.layout.customview_main);
           Button mEvButton=(Button)findViewById(R.id.event_btn);
           mEvButton.setOnClickListener(this);
           mEvButton.setOnTouchListener(this);   
    }
      @Override
      public void onClick(View v) {
        // TODO Auto-generated method stub
        switch (v.getId()) {
            case R.id.event_btn:
            Log.d("Event", "Button----> onClick" );
            break;
            default:
            break;
        }
    }
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        // TODO Auto-generated method stub
        if (v.getId() == R.id.event_btn){
            switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                Log.d("Event", "Button----> onTouch, Action_DOWN" );
                break;

            case MotionEvent.ACTION_UP:
                Log.d("Event", "Button----> onTouch, Action_UP" );
                break;
            case MotionEvent.ACTION_MOVE:
                Log.d("Event", "Button----> onTouch, Action_Move" );
                break;
            case MotionEvent.ACTION_CANCEL:
                Log.d("Event", "Button----> onTouch, Action_Cancel" );
                break;
            default:
                break;
            }
        }
        return false;
    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // TODO Auto-generated method stub
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            Log.d("Event", "Activity----> onTouch, Action_DOWN" );
            break;

        case MotionEvent.ACTION_UP:
            Log.d("Event", "Activity----> onTouch, Action_UP" );
            break;
        case MotionEvent.ACTION_MOVE:
            Log.d("Event", "Activity----> onTouch, Action_Move" );
            break;
        case MotionEvent.ACTION_CANCEL:
            Log.d("Event", "Activity----> onTouch, Action_Cancel" );
            break;
        default:
            break;
        }
        return super.onTouchEvent(event);
    }

자, 먼저 위의 코드를 분석해 봅시다. 길어 보이지만 논리는 간단합니다.MyLinearLayout과 MyButton이 터치와 클릭 감청을 동시에 실현했다.MyLinearLayout 소모 이벤트(Intercept 방법은false로 되돌아오기)3: MyButton의 onTouch 감청은false로 되돌아오고 onTouch Event 방법은super로 돌아갑니다.onTouchEvent.
를 실행하면 인쇄된 로그가 다음과 같습니다.
1: D/Event(2256): MyLinearLayout----> dispatchTouchEvent, Action_DOWN 2: D/Event(2256): MyLinearLayout----> onInterceptTouchEvent, Action_DOWN 3: D/Event(2256): MyButton-----> dispatchTouchEvent, Action_DOWN 4: D/Event(2256): Button----> onTouch, Action_DOWN 5: D/Event(2256): MyButton-----> onTouchEvent, Action_DOWN 6: D/Event(2256): MyButton----->onTouchEvent: return value is true 7: D/Event(2256): MyLinearLayout---->dispatchTouchEvent: return value is true 8: D/Event(2256): MyLinearLayout----> dispatchTouchEvent, Action_UP 9: D/Event(2256): MyLinearLayout----> onInterceptTouchEvent, Action_UP 10: D/Event(2256): MyButton-----> dispatchTouchEvent, Action_UP 11: D/Event(2256): Button----> onTouch, Action_UP 12: D/Event(2256): MyButton-----> onTouchEvent, Action_UP 13: D/Event(2256): MyButton----->onTouchEvent: return value is true 14: D/Event(2256): MyLinearLayout---->dispatchTouchEvent: return value is true 15: D/Event(2256): Button----> onClick
WOWN 이벤트는 View Group의 디스패치 터치 이벤트(첫 번째 줄)에 먼저 전달됩니다. 다음 단계는 모든 DOWN이 온인터내셔널 터치 이벤트(두 번째 줄)에 들어가고false로 돌아가 계속 아래로 나눠집니다. MyButton의 디스패치 터치 이벤트(세 번째 줄)에 들어가면 MyButton은 단일 뷰입니다. 디스패치에 들어간 후에 온터치 리스트를 설정했는지 먼저 판단합니다. 그러면 온터치 방법(네 번째 줄)에 들어갑니다.여기에서 우리는false를 되돌려주고 계속 아래로 전달하며 온터치 이벤트(다섯 번째 줄)에 들어간다. 뷰의 온터치 이벤트 방법을 보면 알 수 있다. 왜냐하면 Button은 CLICKABLE이기 때문에 되돌려주는 값은true(여섯 번째 줄)이고 DOWN 이벤트는 이곳에서 소비된다. 되돌려주는 값true는 View Group, MyLinear Layout의 디스패치는true, DOWN 이벤트가 끝난다(7번째 줄).
그런 다음 UP 이벤트가 발생하면 디스패치(8 행)로 이동합니다.위의 View Group 분석 결론 2에 따르면 DOWN은 서브뷰 처리에 맡겼고 후속 이벤트(UP)는 인터셉트(9번째 줄)에 계속 들어갔다. 되돌아온 것은false이다. 이벤트를 차단하지 않고 계속 아래로 나누어 MyButton의dispatchTouchEvent(10번째 줄)에 도착한 다음에 DOWN 이벤트와 같이 순차적으로onTouch,onTouchEvent,true로 돌아간다.마지막으로 onClick 방법을 실행했는데 윗글에서 View에 대한 분석을 통해 UP만이 Click을 유발할 수 있다는 것을 알았기 때문에 마지막으로 인쇄한 것은 Click이다.
이제 button의 onTouch 방법을 수정하고true로 돌아가 Log를 다시 한 번 살펴보면 Button의 onTouch Event와 클릭 방법이 실행되지 않을 것입니다. 왜냐하면 onTouch가 이벤트를 차단했기 때문에 onTouch Event에 전달되지 않습니다.
다음에 MyLinearLayout에서 이벤트를 차단하는 경우 인터셉트를true로 되돌려줍니다. Log는 다음과 같습니다.
1: MyLinearLayout----> dispatchTouchEvent, Action_DOWN
2: MyLinearLayout----> onInterceptTouchEvent, Action_DOWN 3: MyLinearLayout----> onTouch, Action_DOWN 4: MyLinearLayout----> onTouchEvent, Action_DOWN 5: MyLinearLayout---->onTouchEvent: return value is true 6: MyLinearLayout---->dispatchTouchEvent: return value is true 7: MyLinearLayout----> dispatchTouchEvent, Action_UP 8: MyLinearLayout----> onTouch, Action_UP 9: MyLinearLayout----> onTouchEvent, Action_UP 10�:MyLinearLayout---->onTouchEvent: return value is true 11: :MyLinearLayout---->dispatchTouchEvent: return value is true 12: MyLinearLayout----> onClick,
이를 통해 알 수 있듯이 Linear Layout은 사건을 차단하고 자신에게 맡겼기 때문에 후속 사건 UP는 인터셉트에 들어가지 않고 자신의 온터치에 직접 맡겼다. 온터치가 false로 되돌아왔기 때문에 온터치 이벤트와 온클릭에게 계속 맡긴다.
다른 경우 Button의 온터치와 온터치 이벤트를 모두false로 되돌려보내면 MyLinearLayout에서 이벤트(intercept가false로 되돌려준다)를 소비하지 않아도 이벤트는 MyLinearLayout에 맡겨 처리됩니다.
마지막 경우, 모든 View가 이벤트를 차단하지 않고, 수동으로 되돌아오는 값을 모두false로 변경합니다.실행하면 이벤트가 최종적으로Activity의 onTouchEvent로 전달된다는 것을 알 수 있습니다.

좋은 웹페이지 즐겨찾기