Android 는 소스 코드 의 측면 에서 이벤트 배포 메커니즘 의 해석 을 철저히 이해 합 니 다(하)
14155 단어 android이벤트 배포 메커니즘
아직 읽 지 못 한 친 구 는 먼저 참고 하 세 요Android 는 소스 코드 의 측면 에서 사건 배포 메커니즘 의 해석 을 철저히 이해 합 니 다..
그러면 오늘 우 리 는 지난번 에 완성 되 지 않 은 화 제 를 계속 하고 소스 코드 의 측면 에서 View Group 의 사건 을 분석 하여 배포 할 것 이다.
우선 뷰 그룹 이 무엇 인지 논의 해 볼 까요?그것 은 일반적인 View 와 어떤 차이 가 있 습 니까?
말 그대로 ViewGroup 은 View 의 집합 으로 하위 View 와 하위 Vew Group 이 많이 포함 되 어 있 으 며 Android 의 모든 레이아웃 의 부모 클래스 나 간접 부모 클래스 로 LinearLayout,RelativeLayout 등 은 ViewGroup 에서 계승 되 었 다.그러나 ViewGroup 은 실제 적 으로 View 이기 도 합 니 다.다만 View 보다 하위 View 와 레이아웃 매개 변 수 를 정의 할 수 있 는 기능 이 많 습 니 다.ViewGroup 계승 구조 설명 도 는 다음 과 같다.
우리 가 평소에 프로젝트 에서 자주 사용 하 는 여러 가지 구 조 는 모두 View Group 의 하위 클래스 에 속 하 는 것 을 볼 수 있다.
뷰 그룹 에 대한 간단 한 소 개 를 마 쳤 습 니 다.안 드 로 이 드 에서 Vew Group 의 이벤트 배포 절 차 를 데모 로 보 여 드 리 겠 습 니 다.
먼저 저 희 는 하나의 레이아웃 을 정의 하고 MyLayout 라 고 명명 하 며 LinearLayout 에서 계승 합 니 다.다음 과 같 습 니 다.
public class MyLayout extends LinearLayout {
public MyLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
}
그리고 메 인 레이아웃 파일 activity 열기main.xml,사용자 정의 레이아웃 을 추가 합 니 다:
<com.example.viewgrouptouchevent.MyLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/my_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<Button
android:id="@+id/button1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button1" />
<Button
android:id="@+id/button2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button2" />
</com.example.viewgrouptouchevent.MyLayout>
MyLayout 에 두 개의 단 추 를 추 가 했 습 니 다.이 어 MainActivity 에서 이 두 개의 단추 와 MyLayout 에 감청 이 벤트 를 등록 하 였 습 니 다.
myLayout.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
Log.d("TAG", "myLayout on touch");
return false;
}
});
button1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Log.d("TAG", "You clicked button1");
}
});
button2.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Log.d("TAG", "You clicked button2");
}
});
우 리 는 MyLayout 의 onTouch 방법 과 Button 1,Button 2 의 onClick 방법 에서 한 마디 를 인쇄 했다.현재 항목 을 실행 합 니 다.효과 도 는 다음 과 같 습 니 다.각각 Button 1,Button 2 와 공백 구역 을 클릭 하고 인쇄 결 과 는 다음 과 같 습 니 다.
버튼 을 눌 렀 을 때 MyLayout 에 등 록 된 onTouch 방법 은 실행 되 지 않 고 빈 영역 을 눌 렀 을 때 만 실행 되 는 것 을 발견 할 수 있 습 니 다.Button 의 onClick 방법 으로 사건 을 소비 하 는 것 으로 이해 할 수 있 기 때문에 사건 은 더 이상 아래로 전달 되 지 않 습 니 다.
그러면 안 드 로 이 드 의 터치 이 벤트 는 뷰 에 먼저 전달 되 고 뷰 그룹 에 전달 되 는 것 입 니까?지금 결론 을 내리 기 에는 아직 이르다.우리 다시 실험 을 하 자.
문 서 를 보면 ViewGroup 에 onInterceptTouchEvent 방법 이 있 습 니 다.이 방법의 소스 코드 를 살 펴 보 겠 습 니 다.
/**
* Implement this method to intercept all touch screen motion events. This
* allows you to watch events as they are dispatched to your children, and
* take ownership of the current gesture at any point.
*
* <p>Using this function takes some care, as it has a fairly complicated
* interaction with {@link View#onTouchEvent(MotionEvent)
* View.onTouchEvent(MotionEvent)}, and using it requires implementing
* that method as well as this one in the correct way. Events will be
* received in the following order:
*
* <ol>
* <li> You will receive the down event here.
* <li> The down event will be handled either by a child of this view
* group, or given to your own onTouchEvent() method to handle; this means
* you should implement onTouchEvent() to return true, so you will
* continue to see the rest of the gesture (instead of looking for
* a parent view to handle it). Also, by returning true from
* onTouchEvent(), you will not receive any following
* events in onInterceptTouchEvent() and all touch processing must
* happen in onTouchEvent() like normal.
* <li> For as long as you return false from this function, each following
* event (up to and including the final up) will be delivered first here
* and then to the target's onTouchEvent().
* <li> If you return true from here, you will not receive any
* following events: the target view will receive the same event but
* with the action {@link MotionEvent#ACTION_CANCEL}, and all further
* events will be delivered to your onTouchEvent() method and no longer
* appear here.
* </ol>
*
* @param ev The motion event being dispatched down the hierarchy.
* @return Return true to steal motion events from the children and have
* them dispatched to this ViewGroup through onTouchEvent().
* The current target will receive an ACTION_CANCEL event, and no further
* messages will be delivered here.
*/
public boolean onInterceptTouchEvent(MotionEvent ev) {
return false;
}
만약 원본 코드 를 보지 않 는 다 면 너 는 정말 이 주석 에 놀 랐 을 것 이다.이렇게 긴 영어 주석 을 보 니 머리 가 크다.그런데 소스 코드 가 이렇게 간단 하 다 니!코드 가 한 줄 밖 에 없어 서 false 를 되 돌려 주 었 습 니 다!좋 습 니 다.불 형의 귀환 이 라면 두 가지 가능성 만 있 습 니 다.우 리 는 MyLayout 에서 이 방법 을 다시 쓴 다음 에 true 로 돌아 가 보 겠 습 니 다.코드 는 다음 과 같 습 니 다.
public class MyLayout extends LinearLayout {
public MyLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return true;
}
}
현재 항목 을 다시 실행 한 다음 에 각각 Button 1,Button 2 와 공백 구역 을 각각 실행 합 니 다.인쇄 결 과 는 다음 과 같 습 니 다.당신 은 어디 를 클릭 하 든 MyLayout 의 touch 사건 만 촉발 할 수 있 습 니 다.버튼 의 클릭 사건 이 완전히 차단 되 었 습 니 다!왜 그 럴 까요?Android 의 touch 이벤트 가 View 에 먼저 전달 되 고 View Group 에 전달 된다 면 MyLayout 는 Button 의 클릭 이 벤트 를 어떻게 차단 할 수 있 습 니까?
원본 코드 를 읽 고 Android 에서 View Group 의 사건 배포 체 제 를 파악 해 야 우리 마음속 의 의혹 을 해결 할 수 있 을 것 같 습 니 다.하지만 여기 서 먼저 말씀 드 리 고 싶 습 니 다.Android 에서 touch 사건 의 전달 은 View Group 에 먼저 전달 되 고 View 에 전달 되 는 것 입 니 다.Android 는 소스 코드 의 측면 에서 사건 배포 메커니즘 의 해석 을 철저히 이해 합 니 다.에서 제 가 설명 한 적 이 있 습 니 다.모든 컨트롤 을 만 지면 이 컨트롤 의 dispatch Touch Event 방법 을 반드시 호출 할 것 입 니 다.이 견 해 는 틀림없다.단지 아직 완전 하지 않 을 뿐이다.실제 상황 은 컨트롤 을 클릭 하면 먼저 이 컨트롤 이 있 는 레이아웃 의 dispatchTouchEvent 방법 을 호출 한 다음 에 레이아웃 의 dispatchTouchEvent 방법 에서 클릭 된 해당 컨트롤 을 찾 은 다음 에 이 컨트롤 의 dispatchTouchEvent 방법 을 호출 합 니 다.만약 우리 가 MyLayout 의 단 추 를 눌 렀 다 면,먼저 MyLayout 의 dispatch TouchEvent 방법 을 호출 할 것 입 니 다.그러나 MyLayout 에는 이 방법 이 없다 는 것 을 알 게 될 것 입 니 다.아버지 류 인 리 니 어 라 이 엇 에서 찾 아 보 니 방법 이 없 었 다.LinearLayout 의 부모 클래스 인 View Group 을 계속 찾 을 수 밖 에 없습니다.드디어 View Group 에서 이 방법 을 보 았 습 니 다.버튼 의 dispatch Touch Event 방법 은 바로 여기 서 호출 된 것 입 니 다.수 정 된 설명도 는 다음 과 같다.
그럼 뭘 더 기 다 려?View Group 의 dispatch TouchEvent 방법의 소스 코드 를 보 세 요!코드 는 다음 과 같다.
public boolean dispatchTouchEvent(MotionEvent ev) {
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) {
mMotionTarget = null;
}
if (disallowIntercept || !onInterceptTouchEvent(ev)) {
ev.setAction(MotionEvent.ACTION_DOWN);
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)) {
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)) {
mMotionTarget = child;
return true;
}
}
}
}
}
}
boolean isUpOrCancel = (action == MotionEvent.ACTION_UP) ||
(action == MotionEvent.ACTION_CANCEL);
if (isUpOrCancel) {
mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
}
final View target = mMotionTarget;
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);
}
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)) {
}
mMotionTarget = null;
return true;
}
if (isUpOrCancel) {
mMotionTarget = null;
}
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);
}
이 방법 은 코드 가 비교적 길 어서 우 리 는 중점 만 골 라 본다.우선 13 줄 에서 조건 판단 을 볼 수 있 습 니 다.disallow Intercept 과!onIntercept TouchEvent(ev)둘 중 하 나 는 true 이 고 이 조건 판단 에 들 어 갑 니 다.disallow Intercept 은 이벤트 차단 기능 을 사용 하지 않 을 지 여부 입 니 다.기본 값 은 false 이 며,requestDisallow Intercept TouchEvent 방법 을 호출 하여 이 값 을 수정 할 수 있 습 니 다.그러면 첫 번 째 값 이 false 일 때 두 번 째 값 에 전적으로 의존 하여 조건 판단 의 내부 에 들 어 갈 수 있 는 지,두 번 째 값 은 무엇 입 니까?onInterceptTouchEvent 방법 에 대한 반환 값 을 반대 하 다 니!즉,우리 가 onIntercept TouchEvent 방법 에서 false 를 되 돌려 주면 두 번 째 값 을 true 로 하여 금 조건 판단 의 내부 로 들 어가 게 하고,만약 우리 가 onIntercept TouchEvent 방법 에서 true 로 되 돌아 가면 두 번 째 값 을 false 로 하여 금 이 판단 에서 벗 어 나 게 할 것 이다.이 럴 때 생각해 보 세 요.우리 가 방금 MyLayout 에서 onIntercept TouchEvent 방법 을 다시 썼 기 때문에 이 방법 을 true 로 되 돌려 주 고 모든 버튼 의 클릭 사건 이 차단 되 었 습 니 다.그러면 우 리 는 버튼 을 누 르 면 사건 의 처리 가 바로 제1 3 행 조건 판단 내부 에서 이 루어 진 것 이 라 고 믿 을 이유 가 있 습 니 다!
그럼 조건 판단 의 내부 가 어떻게 이 루어 졌 는 지 에 중점 을 두 자.19 번 째 줄 에서 하나의 for 순환 을 통 해 현재 View Group 의 모든 하위 View 를 옮 겨 다 니 고 24 번 째 줄 에서 현재 옮 겨 다 니 는 View 가 클릭 하고 있 는 View 인지 아 닌 지 를 판단 합 니 다.그렇다면 이 조건 이 판단 하 는 내부 로 들 어가 29 번 째 줄 에서 이 View 의 dispatch Touch Event 를 호출 했 습 니 다.그 후의 절 차 는Android 는 소스 코드 의 측면 에서 사건 배포 메커니즘 의 해석 을 철저히 이해 합 니 다.에서 설명 한 것 과 같 습 니 다.버튼 을 눌 러 사건 을 처리 하 는 것 이 여기 서 이 루어 진 것 이 확실 하 다 는 것 도 확인 됐다.
그리고 하위 View 의 dispatchTouchEvent 를 호출 하면 반환 값 이 있 습 니 다.하나의 컨트롤 이 클릭 할 수 있다 면 이 컨트롤 을 클릭 할 때 dispatchTouchEvent 의 반환 값 은 반드시 true 라 는 것 을 알 고 있 습 니 다.따라서 29 번 째 줄 의 조건 판단 이 성립 될 수 있 기 때문에 31 번 째 줄 에서 View Group 의 dispatch Touch Event 방법 을 트 루 로 되 돌려 주 었 다.이 로 인해 뒤의 코드 가 실행 되 지 못 하 게 되 었 고 우리 앞의 Demo 가 인쇄 한 결과 이기 도 합 니 다.버튼 의 클릭 이벤트 가 실행 되면 MyLayout 의 touch 이 벤트 를 차단 합 니 다.
그럼 우리 가 누 른 것 이 버튼 이 아니 라 공백 구역 이 라면?이 경우 31 줄 에서 트 루 로 돌아 가지 않 고 뒤의 코드 를 계속 실행 할 것 이다.그러면 우 리 는 계속 뒤 를 돌아 보 겠 습 니 다.44 번 째 줄 에서 target 이 null 과 같 으 면 이 조건 으로 내부 판단 에 들 어 갑 니 다.여 기 는 일반적인 상황 에서 target 이 null 이기 때문에 50 번 째 줄 에서 슈퍼 dispatchTouchEvent(ev)를 호출 합 니 다.이 코드 는 어디로 호출 됩 니까?당연히 View 의 dispatchTouchEvent 방법 입 니 다.View Group 의 부 류 는 View 이기 때 문 입 니 다.이후 의 처리 논 리 는 앞에서 말 한 것 과 같 기 때문에 MyLayout 에 등 록 된 onTouch 방법 이 실 행 됩 니 다.그 후의 코드 는 일반적인 상황 에서 갈 수 없 기 때문에 우 리 는 더 이상 분석 하지 않 을 것 이다.
전체 View Group 이벤트 배포 과정의 흐름 도 를 다시 한 번 살 펴 보 세 요.여러분 들 이 더 잘 이해 할 수 있 을 거 라 고 믿 습 니 다.
이제 전체 View Group 의 사건 배포 절차 에 대한 분석 도 여기 서 끝 났 습 니 다.마지막 으로 간단하게 정리 하 겠 습 니 다.
1.안 드 로 이 드 이벤트 배 포 는 뷰 그룹 에 먼저 전달 되 고 뷰 그룹 에서 뷰 로 전 달 됩 니 다.
2.ViewGroup 에서 onInterceptTouchEvent 방법 을 통 해 사건 전달 을 차단 할 수 있 습 니 다.onInterceptTouchEvent 방법 은 true 대표 에 게 사건 이 계속 하위 View 에 전달 되 는 것 을 허락 하지 않 습 니 다.false 대표 로 돌아 가 사건 을 차단 하지 않 고 기본적으로 false 로 돌아 갑 니 다.
3.서브 뷰 에서 전 달 된 이 벤트 를 소비 하면 ViewGroup 에 서 는 이 벤트 를 받 아들 일 수 없습니다.
자,안 드 로 이 드 사건 배포 체 제 는 여기까지 완전히 해석 되 었 습 니 다.상하 두 편 과 결합 하여 여러분 들 이 사건 배포 에 대한 이해 가 매우 깊 어 졌 다 고 믿 습 니 다.
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Kotlin의 기초 - 2부지난 글에서는 Kotlin이 무엇인지, Kotlin의 특징, Kotlin에서 변수 및 데이터 유형을 선언하는 방법과 같은 Kotlin의 기본 개념에 대해 배웠습니다. 유형 변환은 데이터 변수의 한 유형을 다른 데이터...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.