Android 이벤트 의 배포,차단,실행 에 대한 자세 한 설명
Android 의 터치 이벤트 배포 과정 은 세 가지 중요 한 방법 으로 공동으로 이 루어 집 니 다.dispatchTouchEvent,onInterceptTouchEvent,onTouchEvent.나 는 먼저 이 세 가지 방법 을 대체적으로 소개 하 겠 다.
•public boolean dispatchTouchEvent(MotionEvent ev)
사건 의 배 포 를 진행 하 다.이벤트 가 현재 View 에 전 달 될 수 있다 면 이 방법 은 반드시 호출 될 것 입 니 다.결 과 는 현재 View 의 onTouchEvent 와 하급 View 의 dispatchTouchEvent 방법의 영향 을 받 아 현재 이 벤트 를 소모 하 는 지 여 부 를 나 타 냅 니 다.ACTION_DOWN 의 dispatchTouchEvent()복귀 true,후속 이벤트(ACTIONMOVE、ACTION_UP)는 다시 전 달 됩 니 다.false 로 돌아 가면 dispatchTouchEvent()는 ACTION 을 받 지 못 합 니 다.UP、ACTION_MOVE。쉽게 말 하면 dispatchTouchEvent 가 이벤트 배 포 를 진행 할 때 이전 action 이 true 로 돌아 와 야 다음 action 을 촉발 할 수 있다 는 것 이다.
•public boolean onInterceptTouchEvent(MotionEvent event)
이 방법 은 dispatchTouchEvent 방법 에서 호출 되 어 어떤 사건 을 차단 하 는 데 사 용 됩 니 다.현재 View 가 어떤 사건 을 차단 했다 면 같은 사건 시퀀스 에서 이 방법 은 다시 호출 되 지 않 고 돌아 온 결 과 는 현재 사건 을 차단 할 지 여 부 를 표시 합 니 다.이것 은 ViewGroup 이 제공 하 는 방법 입 니 다.기본적으로 false 로 돌아 갑 니 다.
•public boolean onTouchEvent(MotionEvent event)
dispatchTouchEvent 방법 에서 호출 되 었 습 니 다.클릭 이 벤트 를 처리 하 는 데 사 용 됩 니 다.결 과 를 되 돌려 주 는 것 은 현재 이벤트 가 소모 되 었 는 지 여부 입 니 다(true 는 소 모 를 표시 하고 false 는 소모 되 지 않 음 을 표시 합 니 다).소모 되 지 않 으 면 같은 이벤트 시퀀스 에서 현재 View 는 이 벤트 를 다시 받 을 수 없습니다.View 와 View Group 은 모두 이 방법 을 가지 고 있 습 니 다.View 는 기본적으로 true 로 돌아 가 이 사건 을 소 비 했 음 을 표시 합 니 다.
View 에 두 개의 반전 함수 가 있 습 니 다.
public boolean dispatchTouchEvent(MotionEvent ev);
public boolean onTouchEvent(MotionEvent ev);
ViewGroup 에 세 개의 반전 함수 가 있 습 니 다.
public boolean dispatchTouchEvent(MotionEvent ev);
public boolean onInterceptTouchEvent(MotionEvent ev);
public boolean onTouchEvent(MotionEvent ev);
상술 한 세 가지 방법 중 어떤 차이 와 관계 가 있 습 니까?다음은 의사 코드 로 표시 합 니 다.
public boolean dispatchTouchEvent(MotionEvent ev) {
boolean consume = false;
if(onInterceptTouchEvent(ev)){
consume = onTouchEvent(ev);
} else {
consume = child.dispatchTouchEvent(ev);
}
return consume;
}
위의 위조 코드 를 통 해 여러분 은 클릭 이벤트 의 전달 규칙 에 대해 더욱 명확 한 인식 을 가지 게 될 것 입 니 다.즉,하나의 ViewGroup 에 있어 클릭 이벤트 가 발생 한 후에 먼저 전달 할 것 입 니 다.이때 dispatchTouchEvent 는 호출 될 것 입 니 다.만약 에 이 ViewGroup 의 onInterceptTouchEvent 방법 이 true 로 돌아 가면 이 사건 을 차단 하 겠 다 고 표시 합 니 다.이 어 이 사건 은 이 View Group 에 맡 길 것 입 니 다.즉,onTouchEvent 방법 이 호출 될 것 입 니 다.이 View Group 의 onInterceptTouchEvent 방법 이 false 로 돌아 가면 이 사건 을 막 지 않 는 다 는 뜻 입 니 다.이것 은 현재 이벤트 가 하위 요소 에 계속 전 달 될 것 입 니 다.이 어 하위 요소 의 dispatchTouchEvent 방법 이 호출 될 것 입 니 다.이 는 이벤트 가 최종 처 리 될 때 까지 반복 합 니 다.아래 의 몇 장의 그림 은[eoe]에서 참고 한다.
•그림 1:ACTION다운 이 가 소 비 를 안 당 했 어 요.
•그림 2(1):ACTION다운 이 뷰 에 소비 됐어 요.
•그림 2(2):후속 ACTIONMOVE 와 UP 은 차단 되 지 않 은 상태 에서 모두 VIEW 를 찾 아 갑 니 다.
•그림 3:후속 적 인 차단
•그림 4:ACTIONDOWN 은 처음부터 차단 당 했 어 요.
View 이벤트 배포 소스 분석:
•dispatchTouchEvent 방법:
public boolean dispatchTouchEvent(MotionEvent event) {
if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED && mOnTouchListener.onTouch(this, event)) {
return true;
}
return onTouchEvent(event);
}
mOnTouchListener!=null,(mViewFlags&ENABLED_MASK)==ENABLED 와 mOnTouch Listener.onTouch(this,event)라 는 세 가지 조건 이 모두 사실 이면 true 로 돌아 가 고,그렇지 않 으 면 onTouch Event(event)방법 을 실행 하고 돌아 갑 니 다.결론 적 으로 onTouch 가 실 행 될 수 있 는 데 는 두 가지 전제 조건 이 필요 합 니 다(모두 만족 합 니 다).
1.OnTouch Listener 설정
2.컨트롤 은 enable 상태
한편,onTouchEvent 는 다음 과 같은 세 가지 조건 중 하 나 를 만족 시 키 면 됩 니 다.
1.OnTouchListener 가 설정 되 어 있 지 않 음
2.컨트롤 은 enable 상태 가 아 닙 니 다.
3.onTouch 반환 false
다시 한 번 dispatchTouchEvent 의 반환 값 을 살 펴 보 겠 습 니 다.이 는 onTouch 와 onTouchEvent 함수 의 반환 값 에 의 해 제어 되 었 습 니 다.즉,touch 사건 이 성공 적 으로 소비 되 어 true 로 돌아 가면 트 루 로 돌아 가 배포 에 성공 했다 는 것 을 설명 합 니 다.그 후에 사건 서열 도 여기 서 배 포 될 것 입 니 다.만약 에 false 로 돌아 가면 배포 에 실패 했다 고 생각 하고 그 후의 사건 서열 은 더 이상 배포 되 지 않 습 니 다.
•onTouchEvent 방법:
if (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) {
...
return true;
}
View 의 onTouch Event 는 기본적으로 이벤트(이 방법 은 true 로 되 돌아 갑 니 다)를 소모 합 니 다.클릭 할 수 없 는 것 이 아니라면(clickable 과 longClickable 이 동시에 false).또한 View 의 longClickable 기본 값 은 false 이 고 clickable 속성 은 상황 에 따라 달라 집 니 다.예 를 들 어 Button 기본 값 은 true 이 고 TextView,ImageView 기본 값 은 false 입 니 다.
public boolean performClick() {
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
if (mOnClickListener != null) {
playSoundEffect(SoundEffectConstants.CLICK);
mOnClickListener.onClick(this);
return true;
}
return false;
}
이것 이 바로 우리 가 잘 아 는 OnClickListener 가 아 닙 니까?그것 은 원래 onTouchEvent 에서 호출 되 었 습 니 다.mOnClickListener 가 null 이 아니라면 onClick 방법 을 호출 합 니 다.요약 하면 onClick 이 실 행 될 수 있 는 데 는 두 가지 전제 조건 이 필요 합 니 다(모두 만족 합 니 다).
1.onTouchEvent 까지 실행 가능
2.OnClickListener 설정
전체 View 의 이벤트 전송 절 차 는:
dispatchEvent->setOnTouchListener->onTouchEvent->setOnClickListener
마지막 으로 질문 이 하나 더 있 습 니 다.setOnLongClickListener 와 setOnClickListener 는 하나만 실행 할 수 있 습 니까?
답:아 닙 니 다.setOnLongClickListener 의 onClick 이 false 로 돌아 가면 둘 다 실 행 됩 니 다.트 루 로 돌아 가면 setOnClickListener 를 차단 합 니 다.
ViewGroup 이벤트 배포 소스 분석:
•dispatchTouchEvent 방법:
...
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)) {
// Event handled, we have a target now.
mMotionTarget = child;
return true;
}
}
}
}
}
두 가지 가 if 코드 세그먼트 에 들 어 갈 수 있 습 니 다(즉,이벤트 가 하위 View 에 배 포 됩 니 다).1.현재 차단 을 허용 하지 않 습 니 다.즉,disallowIntercept=true 입 니 다.
2.현재 차단 되 지 않 았 습 니 다.즉,onInterceptTouchEvent(ev)는 false 로 돌아 갑 니 다.
주:disallow Intercept 은 이벤트 차단 기능 을 사용 하지 않 을 지 여부 입 니 다.기본 값 은 false 입 니 다.ViewGroup.requestDisallow Intercept TouchEvent(boolean)를 통 해 설정 할 수 있 습 니 다.onInterceptTouchEvent(ev)는 복사 할 수 있 습 니 다.
if 코드 세그먼트 에 들 어간 후 하나의 for 순환 을 통 해 현재 View Group 의 모든 하위 View 를 옮 겨 다 니 며 현재 옮 겨 다 니 는 View 가 클릭 하고 있 는 View 인지 판단 합 니 다.그렇다면 이 View 의 dispatchTouchEvent 를 호출 하여 View 의 이벤트 배포 절차 에 들 어 갑 니 다.child.dispatchTouchEvent(ev)가 true 로 돌아 오 면 mMotionTarget=child 입 니 다.그리고 return true 는 ViewGroup 의 dispatchTouchEvent 반환 값 이 childView 의 dispatchTouchEvent 반환 값 의 영향 을 받 아 하위 view 이벤트 가 성공 적 으로 배포 되 었 고 ViewGroup 의 이벤트 배포 가 성공 적 이 었 다 는 것 을 설명 합 니 다.그 다음 에 이벤트 시퀀스 도 여기 서 배 포 됩 니 다(위 에서 알 수 있 듯 이 하위 view 의 clickable 또는 longClickable 은 true 로 모두 배 포 될 수 있 습 니 다).한편,ViewGroup 이벤트 배포 에 실 패 했 거나 하위 View(빈 위 치 를 클릭)를 찾 지 못 하면 onTouchEvent 로 갑 니 다.이후 이벤트 시퀀스 도 배포 되 지 않 고 onTouchEvent 로 갑 니 다.
전체 View Group 의 이벤트 전송 절 차 는:
dispatchEvent->onInterceptTouchEvent->child.dispatchEvent->(setOnTouchListener->onTouchEvent)
위의 총 결 은 모두 다음 과 같다.만약 차단 하지 않 았 다 면.그럼 어떻게 차단 하나 요?
•onInterceptTouchEvent
public boolean onInterceptTouchEvent(MotionEvent ev) {
return false;
}
코드 는 간단 합 니 다.한 마디 만 false 로 돌아 갑 니 다.ViewGroup 은 기본적으로 차단 하지 않 습 니 다.차단 이 필요 하 다 면 return true 만 있 으 면 됩 니 다.그러면 이 사건 은 하위 View 에 전달 되 지 않 습 니 다.그리고 DOWN return true 에 있 으 면 DOWN,MOVE,UP 서브 View 는 사건 을 포착 하지 못 합 니 다.만약 당신 이 MOVE return true 에 있다 면,서브 뷰 는 MOVE 와 UP 에서 사건 을 포착 하지 못 할 것 입 니 다.어떻게 차단 되 지 않 습 니까?
ViewGroup 의 onInterceptTouchEvent(ev)가 ACTIONMOVE 시 return true,즉 하위 View 의 MOVE 및 UP 사건 을 차단 합 니 다.이때 서브 뷰 가 MOVE 와 UP 에 호응 할 수 있 기 를 바 랄 때 어떻게 해 야 하나 요?
답:onInterceptTouchEvent 는 ViewGroup 에 정 의 된 것 으로 하위 View 는 수정 할 수 없습니다.Android 는 우리 에 게 차단 을 허용 하 는 지 여 부 를 설정 하 는 방법 을 제공 합 니 다.우 리 는 하위 View 의 dispatchTouchEvent 에 직접 이렇게 씁 니 다.
@Override
public boolean dispatchTouchEvent(MotionEvent event)
{
getParent().requestDisallowInterceptTouchEvent(true);
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
Log.e(TAG, "dispatchTouchEvent ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.e(TAG, "dispatchTouchEvent ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.e(TAG, "dispatchTouchEvent ACTION_UP");
break;
default:
break;
}
return super.dispatchTouchEvent(event);
}
getParent().requestDisallowInterceptTouchEvent(true); 이렇게 하면 ViewGroup 이 MOVE 에서 return true 를 하 더 라 도 서브 뷰 는 MOVE 와 UP 사건 을 포착 할 수 있다.주:ViewGroup 이 onInterceptTouchEvent(ev)ACTION 에 있다 면DOWN 안에 return true 가 있 습 니 다.그러면 자 뷰 는 어 쩔 수 없 이 사건 을 포착 합 니 다!
총결산
코드 프로 세 스에 대해 서 는 이미 정 리 했 습 니 다.
1.ViewGroup 이 이 사건 을 처리 할 수 있 는 View 를 찾 으 면 하위 View 에 직접 맡 기 고 자신의 onTouchEvent 는 촉발 되 지 않 습 니 다.
2.onInterceptTouchEvent(ev)방법 을 복사 하여 하위 View 의 이벤트(즉 return true)를 차단 하고 사건 을 자신 에 게 맡 기 면 자신 이 대응 하 는 onTouchEvent 방법 을 실행 할 수 있 습 니 다.
3.하위 뷰 는 getParent().requestDisallowInterceptTouchEvent(true)를 호출 할 수 있 습 니 다.ViewGroup 이 MOVE 나 UP 사건 을 차단 하 는 것 을 막 습 니 다.
자,그럼 실제 응용 에서 어떤 문 제 를 해결 할 수 있 습 니까?
예 를 들 어 ScrollView 에 EditText 를 끼 워 넣 었 습 니 다.EditText 에 텍스트 내용 이 너무 많 고 범 위 를 초과 할 때 위 에서 아래로 미끄러져 EditText 에 있 는 문 자 를 굴 리 려 고 했 지만 스크롤 하 는 것 이 ScrollView 라 는 것 을 알 게 되 었 습 니 다.이 때 우 리 는 EditText 의 onTouch 이 벤트 를 설정 합 니 다.onTouch 에서 ScrollView 가 내 이 벤트 를 차단 하지 못 하도록 설정 하고 마지막 으로 UP 에서 상 태 를 바 꿉 니 다.
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if ((view.getId() == R.id.tousuContentEditText && canVerticalScroll(tousuContentEditText))) {
view.getParent().requestDisallowInterceptTouchEvent(true);
if (motionEvent.getAction() == MotionEvent.ACTION_UP) {
view.getParent().requestDisallowInterceptTouchEvent(false);
}
}
return false;
}
private boolean canVerticalScroll(EditText editText) {
int scrollY = editText.getScrollY();
int scrollRange = editText.getLayout().getHeight();
int scrollExtent = editText.getHeight() - editText.getCompoundPaddingTop() - editText.getCompoundPaddingBottom();
int scrollDifference = scrollRange - scrollExtent;
if (scrollDifference == 0) {
return false;
}
return (scrollY > 0) || (scrollY < scrollDifference - 1);
}
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Bitrise에서 배포 어플리케이션 설정 테스트하기이 글은 Bitrise 광고 달력의 23일째 글입니다. 자체 또는 당사 등에서 Bitrise 구축 서비스를 사용합니다. 그나저나 며칠 전 Bitrise User Group Meetup #3에서 아래 슬라이드를 발표했...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.