ViewPager 2 미끄럼 충돌 해결 방안
14215 단어 AndroidViewPager2미끄럼 충돌
1.왜 ViewPager 는 미끄럼 충돌 이 없 습 니까?
이 의문 이 있 는 지 모 르 겠 습 니 다.ViewPager 시대 에 ViewPager 내장 ViewPager 는 미끄럼 충돌 이 발생 한 적 이 없습니다.그런데 왜 ViewPager 의 업그레이드 버 전인 ViewPager 2 에서 미끄럼 충돌 이 일 어 났 을까요?이 문 제 를 밝 히 려 면 ViewPager 와 ViewPager 2 의 내부 에 깊이 들 어가 그들의 소스 코드 를 분석 해 야 한다.
미끄럼 충돌 은 onInterceptTouchEvent 방법 에서 처리 해 야 한 다 는 것 을 알 고 있 으 며,자신의 조건 에 따라 사건 을 차단 할 지 여 부 를 결정 합 니 다.ViewPager 의 소스 코드 에서 다음 코드 를 볼 수 있 습 니 다(읽 기 편 하고 코드 가 삭제 되 었 습 니 다).
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
final int action = ev.getAction() & MotionEvent.ACTION_MASK;
if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
//
resetTouch();
return false;
}
switch (action) {
case MotionEvent.ACTION_MOVE: {
// 2 ,
if (xDiff > mTouchSlop && xDiff * 0.5f > yDiff) {
mIsBeingDragged = true;
// Parent View , ViewPager
requestParentDisallowInterceptTouchEvent(true);
setScrollState(SCROLL_STATE_DRAGGING);
} else if (yDiff > mTouchSlop) {
mIsUnableToDrag = true;
}
break;
}
case MotionEvent.ACTION_DOWN: {
if (mScrollState == SCROLL_STATE_SETTLING
&& Math.abs(mScroller.getFinalX() - mScroller.getCurrX()) > mCloseEnough) {
// Down Parent View , ViewPager
requestParentDisallowInterceptTouchEvent(true);
setScrollState(SCROLL_STATE_DRAGGING);
} else {
completeScroll(false);
mIsBeingDragged = false;
}
break;
}
case MotionEvent.ACTION_POINTER_UP:
onSecondaryPointerUp(ev);
break;
}
return mIsBeingDragged;
}
ACTION 에서 보 실 수 있 습 니 다.DOWN 과 ACTIONMOVE 에 서 는 일부 판단 조건 에 따라 requestParent Disallow Intercept TouchEvent(true)방법 을 호출 하여 Parent View 차단 사건 을 금지 하 였 습 니 다.즉,ViewPager 가 미끄럼 충돌 을 처리 해 주 었 기 때문에 우 리 는 사용 만 하면 됩 니 다.미끄럼 충돌 문 제 를 걱정 하지 않 아 도 됩 니 다.현재,우 리 는 ViewPager 2 로 이동 하여 원본 코드 를 뒤 져 보 니 RecyclerView 의 실현 클래스 에 만 onInterceptTouchEvent 와 관련 된 방법 이 있 고,이 코드 는 사용자 가 입력 하지 않 은 논 리 를 처리 하 는 것 일 뿐 입 니 다!
private class RecyclerViewImpl extends RecyclerView {
.... //
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return isUserInputEnabled() && super.onInterceptTouchEvent(ev);
}
}
그 러 니까 ViewPager 2 는 사실 미끄럼 충돌 을 처리 해 주지 않 았 다 는 거 야!왜 그 럴 까요?ViewPager 2 개발 자 들 이 이 일 을 잊 어 버 린 건 가?여 기 는 내 가 장담 하 건 대 틀림없이 이 렇 지 않 을 것 이다.사실 ViewPager 2 의 구 조 를 보면 대충 알 수 있 습 니 다.ViewPager 2 가 final 로 밝 혀 졌 다 는 것 은 ViewPager 2 를 계승 하 는 것 처럼 ViewPager 2 를 수정 할 수 없다 는 것 을 의미한다.만약 에 정부 가 ViewPager 2 내부 에서 미끄럼 충돌 을 자체 적 으로 처리 했다 면 특별한 수요 가 있 으 면 우리 자신의 상황 에 따라 ViewPager 2 의 미끄럼 을 처리 해 야 합 니 다.그러면 공식 적 으로 쓴 미끄럼 충돌 을 처리 하 는 코드 는 우리 자신의 수요 에 영향 을 줄 수 있 습 니까?그래서 저 는 이 때문에 아예 아무런 처리 도 하지 않 고 개발 자 에 게 전권 을 맡 겼 다 고 생각 합 니 다.2.미끄럼 충돌 처리 방안
정부 가 우리 에 게 처리 하지 않 는 이상 우리 스스로 손 을 써 야 한다.시작 하기 전에 미끄럼 충돌 을 처리 하 는 두 가지 방안 을 알 아 보 겠 습 니 다.미끄럼 충돌 이 발생 한 이상 두 레이아웃 이 서로 겹 쳐 서 일어 난 것 이 분명 하 다.두 개의 포석 인 이상 우 리 는 두 방향 으로 나 누 어 처리 할 수 있다.이른바 외부 차단 법 과 내부 차단 법 이다.
1.외부 차단 법
이른바'외부 차단 법'중의 외 부 는 미끄럼 충돌 이 발생 하 는 이 두 구조의 외층 을 가리킨다.우 리 는 하나의 사건 서열 이 Parent View 에서 먼저 얻 은 것 임 을 알 고 있 습 니 다.만약 Parent View 가 사건 을 차단 하지 않 으 면 하위 View 에 의 해 처 리 됩 니 다.외부 에서 먼저 사건 을 알 게 된 이상 외부 View 는 자신의 상황 에 따라 사건 을 차단 할 지 여 부 를 결정 하면 되 지 않 겠 습 니까?따라서 외부 차단 법의 실현 은 매우 간단 하 다.대략적인 사고방식 은 다음 과 같다.
public boolean onInterceptTouchEvent(MotionEvent event) {
boolean intercepted = false;
int x = (int) event.getX();
int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
intercepted = false;
break;
}
case MotionEvent.ACTION_MOVE: {
if (needIntercept) { //
intercepted = true;
} else {
intercepted = false;
}
break;
}
case MotionEvent.ACTION_UP: {
intercepted = false;
break;
}
default:
break;
}
mLastXIntercept = x;
mLastYIntercept = y;
return intercepted;
}
2.내부 차단 법이른바'내부 차단 법'이란 내부 뷰 에 대해 글 을 써 서 내부 뷰 로 하여 금 사건 차단 여 부 를 결정 하 게 하 는 것 을 말한다.그런데 지금 문제 가 생 겼 어 요.외부 View 가 사건 을 차단 하려 는 건 지 어떻게 알았어 요?외부 뷰 가 사건 을 차단 하면 내부 뷰 는 북서풍 도 마 시 지 못 하 는 것 이 아 닙 니까?서 두 르 지 마 세 요.구 글 공식 에 서 는 당연히 이런 상황 을 고려 하고 있 습 니 다.ViewGroup 에 requestDisallow InterceptTouchEvent 라 는 방법 이 있 습 니 다.이 방법 은 boolean 값 을 받 아들 이 는 것 입 니 다.ViewGroup 이 현재 이 벤트 를 차단 하 는 것 을 금지 하 는 지 여부 입 니 다.트 루 라면 이 뷰 그룹 은 사건 을 차단 할 수 없습니다.이 방법 이 있 으 면 우 리 는 내부 뷰 를 크게 놀 라 게 할 수 있다.내부 차단 법의 코드 를 보십시오:
public boolean dispatchTouchEvent(MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
// parent down
parent.requestDisallowInterceptTouchEvent(true);
break;
}
case MotionEvent.ACTION_MOVE: {
int deltaX = x - mLastX;
int deltaY = y - mLastY;
if (disallowParentInterceptTouchEvent) { // Parent View 。
parent.requestDisallowInterceptTouchEvent(false);
}
break;
}
case MotionEvent.ACTION_UP: {
break;
}
default:
break;
}
mLastX = x;
mLastY = y;
return super.dispatchTouchEvent(event);
}
이렇게 처리 하면 두 개의 내장 View 가 조 화 롭 게 작업 할 수 있다.다음은 외부 View 와 내부 View 에서 나 온 대화 입 니 다.
외부 보기:"사건 을 차단 하고 싶 습 니 다!"
내부 View:아니요,싫 습 니 다.이 사건 은 내 가 결정 할 것 이 니 예 수 는 그 를 붙 잡 을 수 없다.
3.ViewPager 2 의 미끄럼 충돌 처리
지난 장 에 서 는 미끄럼 충돌 처리 방안 두 가 지 를 설명 하 였 으 며,이 장 에 서 는 ViewPager 2 의 미끄럼 충돌 을 해결 하 겠 습 니 다.우선 차단 이 필요 하고 차단 이 필요 없 는 경계 조건 이 어디 에 있 는 지 확인 해 야 한다.이 글 을 쓰기 전에 Google 은 ViewPager 2 의 미끄럼 충돌 처리 방안 을 검 색 했 습 니 다.이 부분 에 대한 글 은 적지 않 지만 대부분의 글 은 ViewPager 2 의 미끄럼 충돌 처리 에 대해 완벽 하 게 고려 하지 못 했 습 니 다.
다음은 우리 가 상세 하 게 분석 해 보 자.
class ViewPager2Container @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : RelativeLayout(context, attrs, defStyleAttr) {
private var mViewPager2: ViewPager2? = null
private var disallowParentInterceptDownEvent = true
private var startX = 0
private var startY = 0
override fun onFinishInflate() {
super.onFinishInflate()
for (i in 0 until childCount) {
val childView = getChildAt(i)
if (childView is ViewPager2) {
mViewPager2 = childView
break
}
}
if (mViewPager2 == null) {
throw IllegalStateException("The root child of ViewPager2Container must contains a ViewPager2")
}
}
override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
val doNotNeedIntercept = (!mViewPager2!!.isUserInputEnabled
|| (mViewPager2?.adapter != null
&& mViewPager2?.adapter!!.itemCount <= 1))
if (doNotNeedIntercept) {
return super.onInterceptTouchEvent(ev)
}
when (ev.action) {
MotionEvent.ACTION_DOWN -> {
startX = ev.x.toInt()
startY = ev.y.toInt()
parent.requestDisallowInterceptTouchEvent(!disallowParentInterceptDownEvent)
}
MotionEvent.ACTION_MOVE -> {
val endX = ev.x.toInt()
val endY = ev.y.toInt()
val disX = abs(endX - startX)
val disY = abs(endY - startY)
if (mViewPager2!!.orientation == ViewPager2.ORIENTATION_VERTICAL) {
onVerticalActionMove(endY, disX, disY)
} else if (mViewPager2!!.orientation == ViewPager2.ORIENTATION_HORIZONTAL) {
onHorizontalActionMove(endX, disX, disY)
}
}
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> parent.requestDisallowInterceptTouchEvent(false)
}
return super.onInterceptTouchEvent(ev)
}
private fun onHorizontalActionMove(endX: Int, disX: Int, disY: Int) {
if (mViewPager2?.adapter == null) {
return
}
if (disX > disY) {
val currentItem = mViewPager2?.currentItem
val itemCount = mViewPager2?.adapter!!.itemCount
if (currentItem == 0 && endX - startX > 0) {
parent.requestDisallowInterceptTouchEvent(false)
} else {
parent.requestDisallowInterceptTouchEvent(currentItem != itemCount - 1
|| endX - startX >= 0)
}
} else if (disY > disX) {
parent.requestDisallowInterceptTouchEvent(false)
}
}
private fun onVerticalActionMove(endY: Int, disX: Int, disY: Int) {
if (mViewPager2?.adapter == null) {
return
}
val currentItem = mViewPager2?.currentItem
val itemCount = mViewPager2?.adapter!!.itemCount
if (disY > disX) {
if (currentItem == 0 && endY - startY > 0) {
parent.requestDisallowInterceptTouchEvent(false)
} else {
parent.requestDisallowInterceptTouchEvent(currentItem != itemCount - 1
|| endY - startY >= 0)
}
} else if (disX > disY) {
parent.requestDisallowInterceptTouchEvent(false)
}
}
/**
* View {@link MotionEvent#ACTION_DOWN} View ,
* CoordinatorLayout+CollapsingToolbarLayout ViewPager2Container 。
*
* ViewPager2Container {@link MotionEvent#ACTION_DOWN} View ,
* CoordinatorLayout+CollapsingToolbarLayout ViewPager2Container 。
*
* @param disallowParentInterceptDownEvent ViewPager2Container {@link MotionEvent#ACTION_DOWN} View , false
* true ViewPager2Container {@link MotionEvent#ACTION_DOWN} View ,
* disallowIntercept true CoordinatorLayout+CollapsingToolbarLayout
* false ViewPager2Container {@link MotionEvent#ACTION_DOWN} View ,
*/
fun disallowParentInterceptDownEvent(disallowParentInterceptDownEvent: Boolean) {
this.disallowParentInterceptDownEvent = disallowParentInterceptDownEvent
}
}
위의 코드 는 지면 에 국한 되 어 있 습 니 다.저 는 너무 많은 설명 을 하지 않 겠 습 니 다.onFinish Inflate 에서 우 리 는 순환 을 통 해 ViewPager 2 Container 의 모든 하위 View 를 옮 겨 다 녔 습 니 다.ViewPager 2 를 찾 지 못 하면 이상 을 던 집 니 다.또 disallow Parent InterceptDownEvent 방법 에 대한 설명 은 자세히 쓰 여 있 지 않다.사용 방법 도 간단 합 니 다.ViewPager2Container 로 ViewPager 2 를 직접 감 싸 면 됩 니 다.
<com.zhpan.sample.viewpager2.ViewPager2Container
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/view_pager2"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.zhpan.indicator.IndicatorView
android:id="@+id/indicatorView"
android:layout_centerHorizontal="true"
android:layout_alignParentBottom="true"
android:layout_margin="@dimen/dp_20"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</com.zhpan.sample.viewpager2.ViewPager2Container>
이것 은 ViewPager 2 미끄럼 충돌 에 대한 처리 방안 입 니 다.물론 Banner ViewPager 는 순환 순환 방송 을 지원 하기 때문에 Banner ViewPager 의 미끄럼 충돌 처리 가 상대 적 으로 번 거 로 울 수 있 습 니 다.관심 있 는 친구 가 있 으 면못 배 워 도 배 워 야 지!ViewPager 2 깊이 이해의 소스 코드 를 클릭 하여 볼 수 있다.동시에BannerViewPager의 소스 코드 도 Github 에 넣 었 고 필요 한 것 은 스스로 찾 을 수 있 습 니 다.
이상 은 ViewPager 2 미끄럼 충돌 해결 방안 의 상세 한 내용 입 니 다.ViewPager 2 미끄럼 충돌 해결 에 관 한 자 료 는 저희 의 다른 관련 글 을 주목 해 주 십시오!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 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에 따라 라이센스가 부여됩니다.