Android 중첩 슬라이딩 메커니즘을 통해 상단 레이아웃 상단
1. 문제의 전형적인 장면
일반적으로 정보 흐름(예를 들어 지역사회, 정보, 뉴스) 페이지나 상품 상세 페이지의 상호작용 디자인이다.그림 참조:
코드로 분해되는 것은 일반적인 세 가지 컨트롤이다. 하나는 머리 레이아웃이고 아마도banner.내비게이션 컨트롤다음 내용의 목록 컨트롤입니다.헤드 레이아웃과 네비게이션 레이아웃이 내용 레이아웃에서 일정한 거리(일반적으로 헤드 레이아웃의 높이에 네비게이션 컨트롤의 높이)를 미끄러뜨린 후에 네비게이션 컨트롤을 꼭대기에 놓고 내용 목록을 계속 미끄러져야 한다.
2. 안드로이드 이벤트 배달 메커니즘 처리 문제의 문제점
전통적인 안드로이드 이벤트 분배는 하위 컨트롤러가 이벤트를 소비했기 때문에 부모 컨트롤러는 이 사건을 더 이상 처리할 수 없습니다.즉, 내부의 미끄럼 컨트롤러가 미끄럼 조작을 소비하면 외부의 미끄럼 컨트롤러가 이 미끄럼 동작을 얻지 못하고 처리할 수 없다는 것이다.우리의 이전 상황에서 슬라이딩 내용 목록 컨트롤러는 헤드 레이아웃과 네비게이션 레이아웃에 응답을 요구하는 것은 그들의 공동 아버지 레이아웃에 응답을 요구하는 것이다. 전통적인 사건으로 나누어 처리하는 것은 매우 어려운 것이다.
3. 안드로이드 플러그인 슬라이딩 메커니즘의 기초 개념
스크롤 중의 두 인터페이스는 위에서 언급한 바와 같다.Nested Scrolling Parent와 Nested Scrolling Child 인터페이스의 방법은 다음과 같다. Nested Scrolling Child
하위 뷰가 스크롤 이벤트를 받아들인 후 플러그인 스크롤을 시작합니다. 부모 뷰가 먼저 스크롤을 할지 묻습니다. 부모 뷰가 자신의 스크롤 요구를 처리한 후에 하위 뷰로 돌아가서 자신의 스크롤 요구를 처리합니다. 만약에 부모 뷰가 스크롤 거리를 소모한다면 하위 뷰는 남은 스크롤 거리만 가져와서 처리할 수 있습니다.하위 뷰는 자신의 스크롤 요구 사항을 처리한 후 부모 뷰로 돌아가 나머지 스크롤 거리를 처리합니다.관성fling의 유사.
public boolean startNestedScroll(@ScrollAxis int axes, @NestedScrollType int type) {
if (hasNestedScrollingParent(type)) {
// Already in progress
return true;
}
if (isNestedScrollingEnabled()) {
ViewParent p = mView.getParent();
View child = mView;
while (p != null) {
if (ViewParentCompat.onStartNestedScroll(p, child, mView, axes, type)) {
setNestedScrollingParentForType(type, p);
ViewParentCompat.onNestedScrollAccepted(p, child, mView, axes, type);
return true;
}
if (p instanceof View) {
child = (View) p;
}
p = p.getParent();
}
}
return false;
}
다음은 RecyclerView의 onTouch Event의 Motion Event.ACTION_MOVE에서 디스패치 Nested PreScroll과 scroll By 인터넷이 호출됐어요.
case MotionEvent.ACTION_MOVE: {
if (dispatchNestedPreScroll(dx, dy, mScrollConsumed, mScrollOffset, TYPE_TOUCH)) {
dx -= mScrollConsumed[0];
dy -= mScrollConsumed[1];
vtev.offsetLocation(mScrollOffset[0], mScrollOffset[1]);
// Updated the nested offsets
mNestedOffsets[0] += mScrollOffset[0];
mNestedOffsets[1] += mScrollOffset[1];
}
if (mScrollState == SCROLL_STATE_DRAGGING) {
mLastTouchX = x - mScrollOffset[0];
mLastTouchY = y - mScrollOffset[1];
if (scrollByInternal(
canScrollHorizontally ? dx : 0,
canScrollVertically ? dy : 0,
vtev)) {
getParent().requestDisallowInterceptTouchEvent(true);
}
}
} break;
dispatchNested PreScroll에서 부모 View의 onNested PreScroll을 조정하고dy와consumed로 전송합니다.소비 계수에 쓰다.
public boolean dispatchNestedPreScroll(int dx, int dy, @Nullable int[] consumed,
@Nullable int[] offsetInWindow, @NestedScrollType int type) {
if (isNestedScrollingEnabled()) {
final ViewParent parent = getNestedScrollingParentForType(type);
if (parent == null) {
return false;
}
if (dx != 0 || dy != 0) {
⋯⋯
consumed[0] = 0;
consumed[1] = 0;
ViewParentCompat.onNestedPreScroll(parent, mView, dx, dy, consumed, type);
⋯⋯
return consumed[0] != 0 || consumed[1] != 0;
} else if (offsetInWindow != null) {
offsetInWindow[0] = 0;
offsetInWindow[1] = 0;
}
}
return false;
}
최종적으로 부모 뷰의 onNested PreScroll () 방법이 호출되었습니다.다음 순서에 따라 네스트된 스크롤을 수행하는 방법을 분석할 수 있습니다.
(자)startNestedScroll→(부)onStartNestedScroll→(부)onNestedScrollAccepted→(자)dispatchNestedPreScroll→(부)onNestedPreScroll→(자)dispatchNestedScroll→(부)onNestedScroll→(자)dispatchNestedPreFling→(부)onNestedPreFling→(부)dispatchNestedPreFling→(자)onestedNestedScrollScroll(부))
5. 플러그인 슬라이딩 전형적인 사례 실천
관건적인 방법은 두 가지로 효과를 완성할 수 있다. 단지 경직되고 경직되어 있기 때문에 더욱 좋은 사용자 체험을 위해 제스처 속도의 미끄럼 예판을 넣어야 한다.
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mHeaderView.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
mMaxScrollHeight = mHeaderView.getMeasuredHeight() - mHeaderRetainHeight;
// : match_parent
if (mBodyView.getLayoutParams().height < getMeasuredHeight() - mHeaderRetainHeight) {
mBodyView.getLayoutParams().height = getMeasuredHeight() - mHeaderRetainHeight;
}
setMeasuredDimension(getMeasuredWidth(), mBodyView.getLayoutParams().height + mHeaderView.getMeasuredHeight());
}
onMeasure()에서 머리 레이아웃과 천장 레이아웃 높이를 계산하여 전체 컨트롤의 측정을 완성하고 머리 레이아웃에서 천장 레이아웃의 최대 미끄럼 거리 값을 제거하는 것을 기록합니다.
@Override
public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
boolean hiddenTop = dy > 0 && getScrollY() < mMaxScrollHeight;
boolean showTop = dy < 0 && getScrollY() > 0 && !ViewCompat.canScrollVertically(target, -1);
if (hiddenTop || showTop) {
scrollBy(0, dy);
consumed[1] = dy;
}
}
그리고 이 방법을 다시 쓰면 대응하는 슬라이딩 플러그인을 실현할 수 있다. 즉, 네비게이션 슬롯 컨트롤러를 꼭대기에 놓는 것이다. 사실은 네비게이션 슬롯의 높이를 미리 알고 슬라이딩과 슬라이딩 거리가 최대 슬라이딩 거리보다 크며 슬라이딩이 가능하고 내용 컨트롤러가 슬라이딩이 불가능할 때 모든 슬라이딩 거리를 아버지 컨트롤러에게 건네주는 것이다. 즉, Nested Scroll Parent 인터페이스의 자신을 실현하는 것이다.
상당한 코드는 나의 github 실례를 참고할 수 있다: Sticky Nested Scroll Layout
참고: Android Nested Scrolling 메커니즘 완전 해석
플러그인 스크롤 디자인과 원본 분석
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.