From 0835e9614f6bb6a35fe215417ed751f75d159ac0 Mon Sep 17 00:00:00 2001 From: cgspine Date: Tue, 9 Apr 2019 20:30:32 +0800 Subject: [PATCH] 1.padding support; 2.scroll info save and restore --- .../IQMUIContinuousNestedBottomView.java | 9 +- .../IQMUIContinuousNestedScrollCommon.java | 33 ++++++ .../IQMUIContinuousNestedTopView.java | 8 +- ...MUIContinuousNestedBottomAreaBehavior.java | 16 ++- ...IContinuousNestedBottomDelegateLayout.java | 27 ++++- ...MUIContinuousNestedBottomRecyclerView.java | 40 +++++++ .../QMUIContinuousNestedScrollLayout.java | 103 +++++++++++++++--- .../QMUIContinuousNestedTopAreaBehavior.java | 6 +- ...QMUIContinuousNestedTopDelegateLayout.java | 72 +++++++++--- .../QMUIContinuousNestedTopLinearLayout.java | 10 ++ .../QMUIContinuousNestedTopRecyclerView.java | 40 +++++++ .../QMUIContinuousNestedTopWebView.java | 12 ++ .../fragment/lab/QDContinuousBottomView.java | 30 +++++ 13 files changed, 355 insertions(+), 51 deletions(-) create mode 100644 qmui/src/main/java/com/qmuiteam/qmui/nestedScroll/IQMUIContinuousNestedScrollCommon.java diff --git a/qmui/src/main/java/com/qmuiteam/qmui/nestedScroll/IQMUIContinuousNestedBottomView.java b/qmui/src/main/java/com/qmuiteam/qmui/nestedScroll/IQMUIContinuousNestedBottomView.java index da5c291d..bf2a8f8f 100644 --- a/qmui/src/main/java/com/qmuiteam/qmui/nestedScroll/IQMUIContinuousNestedBottomView.java +++ b/qmui/src/main/java/com/qmuiteam/qmui/nestedScroll/IQMUIContinuousNestedBottomView.java @@ -16,7 +16,7 @@ package com.qmuiteam.qmui.nestedScroll; -public interface IQMUIContinuousNestedBottomView { +public interface IQMUIContinuousNestedBottomView extends IQMUIContinuousNestedScrollCommon { int HEIGHT_IS_ENOUGH_TO_SCROLL = -1; /** * consume scroll @@ -34,11 +34,4 @@ public interface IQMUIContinuousNestedBottomView { int getCurrentScroll(); int getScrollOffsetRange(); - - void injectScrollNotifier(OnScrollNotifier notifier); - - interface OnScrollNotifier { - void notify(int innerOffset, int innerRange); - } - } \ No newline at end of file diff --git a/qmui/src/main/java/com/qmuiteam/qmui/nestedScroll/IQMUIContinuousNestedScrollCommon.java b/qmui/src/main/java/com/qmuiteam/qmui/nestedScroll/IQMUIContinuousNestedScrollCommon.java new file mode 100644 index 00000000..bde72a96 --- /dev/null +++ b/qmui/src/main/java/com/qmuiteam/qmui/nestedScroll/IQMUIContinuousNestedScrollCommon.java @@ -0,0 +1,33 @@ +/* + * Tencent is pleased to support the open source community by making QMUI_Android available. + * + * Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the MIT License (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://opensource.org/licenses/MIT + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.qmuiteam.qmui.nestedScroll; + +import android.support.annotation.Nullable; + +public interface IQMUIContinuousNestedScrollCommon { + + @Nullable + Object saveScrollInfo(); + + void restoreScrollInfo(@Nullable Object scrollInfo); + + void injectScrollNotifier(OnScrollNotifier notifier); + + interface OnScrollNotifier { + void notify(int innerOffset, int innerRange); + } +} diff --git a/qmui/src/main/java/com/qmuiteam/qmui/nestedScroll/IQMUIContinuousNestedTopView.java b/qmui/src/main/java/com/qmuiteam/qmui/nestedScroll/IQMUIContinuousNestedTopView.java index f2924967..7727f202 100644 --- a/qmui/src/main/java/com/qmuiteam/qmui/nestedScroll/IQMUIContinuousNestedTopView.java +++ b/qmui/src/main/java/com/qmuiteam/qmui/nestedScroll/IQMUIContinuousNestedTopView.java @@ -16,7 +16,7 @@ package com.qmuiteam.qmui.nestedScroll; -public interface IQMUIContinuousNestedTopView { +public interface IQMUIContinuousNestedTopView extends IQMUIContinuousNestedScrollCommon { /** * consume scroll * @@ -28,10 +28,4 @@ public interface IQMUIContinuousNestedTopView { int getCurrentScroll(); int getScrollOffsetRange(); - - void injectScrollNotifier(OnScrollNotifier notifier); - - interface OnScrollNotifier { - void notify(int innerOffset, int innerRange); - } } \ No newline at end of file diff --git a/qmui/src/main/java/com/qmuiteam/qmui/nestedScroll/QMUIContinuousNestedBottomAreaBehavior.java b/qmui/src/main/java/com/qmuiteam/qmui/nestedScroll/QMUIContinuousNestedBottomAreaBehavior.java index 24e33338..0097bd3e 100644 --- a/qmui/src/main/java/com/qmuiteam/qmui/nestedScroll/QMUIContinuousNestedBottomAreaBehavior.java +++ b/qmui/src/main/java/com/qmuiteam/qmui/nestedScroll/QMUIContinuousNestedBottomAreaBehavior.java @@ -17,22 +17,26 @@ package com.qmuiteam.qmui.nestedScroll; import android.graphics.Rect; -import android.util.Log; +import android.support.annotation.NonNull; +import android.support.design.widget.CoordinatorLayout; +import android.support.v4.view.GravityCompat; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; import java.util.List; -import androidx.annotation.NonNull; -import androidx.coordinatorlayout.widget.CoordinatorLayout; -import androidx.core.view.GravityCompat; - public class QMUIContinuousNestedBottomAreaBehavior extends QMUIViewOffsetBehavior { private final Rect tempRect1 = new Rect(); private final Rect tempRect2 = new Rect(); + private int mTopInset = 0; + + public void setTopInset(int topInset) { + mTopInset = topInset; + } + @Override public boolean onMeasureChild(@NonNull CoordinatorLayout parent, @NonNull View child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed) { final int childLpHeight = child.getLayoutParams().height; @@ -44,6 +48,8 @@ public class QMUIContinuousNestedBottomAreaBehavior extends QMUIViewOffsetBehavi availableHeight = parent.getHeight(); } + availableHeight -= mTopInset; + final int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec( availableHeight, diff --git a/qmui/src/main/java/com/qmuiteam/qmui/nestedScroll/QMUIContinuousNestedBottomDelegateLayout.java b/qmui/src/main/java/com/qmuiteam/qmui/nestedScroll/QMUIContinuousNestedBottomDelegateLayout.java index b7a475f6..55a00748 100644 --- a/qmui/src/main/java/com/qmuiteam/qmui/nestedScroll/QMUIContinuousNestedBottomDelegateLayout.java +++ b/qmui/src/main/java/com/qmuiteam/qmui/nestedScroll/QMUIContinuousNestedBottomDelegateLayout.java @@ -225,6 +225,32 @@ public abstract class QMUIContinuousNestedBottomDelegateLayout extends QMUIFrame } } + @Override + public void restoreScrollInfo(Object scrollInfo) { + if (scrollInfo instanceof ScrollInfo) { + ScrollInfo si = (ScrollInfo) scrollInfo; + mHeaderViewOffsetHelper.setTopAndBottomOffset(si.topBottomOffset); + mContentViewOffsetHelper.setTopAndBottomOffset(si.topBottomOffset); + ((IQMUIContinuousNestedBottomView) mContentView).restoreScrollInfo(si.delegateScrollInfo); + } + } + + @Override + public Object saveScrollInfo() { + return new ScrollInfo(mHeaderViewOffsetHelper.getTopAndBottomOffset(), + ((IQMUIContinuousNestedBottomView) mContentView).saveScrollInfo()); + } + + public static class ScrollInfo { + int topBottomOffset; + Object delegateScrollInfo; + + public ScrollInfo(int topBottomOffset, Object delegateScrollInfo) { + this.topBottomOffset = topBottomOffset; + this.delegateScrollInfo = delegateScrollInfo; + } + } + // NestedScrollingChild2 @Override @@ -641,6 +667,5 @@ public abstract class QMUIContinuousNestedBottomDelegateLayout extends QMUIFrame removeCallbacks(this); mOverScroller.abortAnimation(); } - } } diff --git a/qmui/src/main/java/com/qmuiteam/qmui/nestedScroll/QMUIContinuousNestedBottomRecyclerView.java b/qmui/src/main/java/com/qmuiteam/qmui/nestedScroll/QMUIContinuousNestedBottomRecyclerView.java index d096c577..71a67d01 100644 --- a/qmui/src/main/java/com/qmuiteam/qmui/nestedScroll/QMUIContinuousNestedBottomRecyclerView.java +++ b/qmui/src/main/java/com/qmuiteam/qmui/nestedScroll/QMUIContinuousNestedBottomRecyclerView.java @@ -20,8 +20,10 @@ import android.content.Context; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.view.ViewCompat; +import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.util.AttributeSet; +import android.view.View; public class QMUIContinuousNestedBottomRecyclerView extends RecyclerView @@ -123,4 +125,42 @@ public class QMUIContinuousNestedBottomRecyclerView extends RecyclerView public int getScrollOffsetRange() { return Math.max(0, computeVerticalScrollRange() - getHeight()); } + + @Override + public Object saveScrollInfo() { + LayoutManager layoutManager = getLayoutManager(); + if (layoutManager instanceof LinearLayoutManager) { + LinearLayoutManager lm = (LinearLayoutManager) layoutManager; + if (lm.getOrientation() == LinearLayoutManager.HORIZONTAL) { + return null; + } + int pos = lm.findFirstVisibleItemPosition(); + View firstView = lm.findViewByPosition(pos); + int offset = firstView == null ? 0 : firstView.getTop(); + return new ScrollInfo(pos, offset); + } + return null; + } + + @Override + public void restoreScrollInfo(Object scrollInfo) { + if (!(scrollInfo instanceof ScrollInfo)) { + return; + } + ScrollInfo sc = (ScrollInfo) scrollInfo; + LayoutManager layoutManager = getLayoutManager(); + if (layoutManager instanceof LinearLayoutManager) { + ((LinearLayoutManager) layoutManager).scrollToPositionWithOffset(sc.scrollPosition, sc.scrollOffset); + } + } + + public static class ScrollInfo { + int scrollPosition; + int scrollOffset; + + public ScrollInfo(int scrollPosition, int scrollOffset) { + this.scrollPosition = scrollPosition; + this.scrollOffset = scrollOffset; + } + } } diff --git a/qmui/src/main/java/com/qmuiteam/qmui/nestedScroll/QMUIContinuousNestedScrollLayout.java b/qmui/src/main/java/com/qmuiteam/qmui/nestedScroll/QMUIContinuousNestedScrollLayout.java index 09ad54c9..fa2b6c8e 100644 --- a/qmui/src/main/java/com/qmuiteam/qmui/nestedScroll/QMUIContinuousNestedScrollLayout.java +++ b/qmui/src/main/java/com/qmuiteam/qmui/nestedScroll/QMUIContinuousNestedScrollLayout.java @@ -106,6 +106,14 @@ public class QMUIContinuousNestedScrollLayout extends CoordinatorLayout implemen return mBottomView; } + public QMUIContinuousNestedTopAreaBehavior getTopAreaBehavior() { + return mTopAreaBehavior; + } + + public QMUIContinuousNestedBottomAreaBehavior getBottomAreaBehavior() { + return mBottomAreaBehavior; + } + public void setBottomAreaView(View bottomView, @Nullable LayoutParams layoutParams) { if (!(bottomView instanceof IQMUIContinuousNestedBottomView)) { throw new IllegalStateException("bottomView must implement from IQMUIContinuousNestedBottomView"); @@ -117,7 +125,7 @@ public class QMUIContinuousNestedScrollLayout extends CoordinatorLayout implemen mBottomView.injectScrollNotifier(new IQMUIContinuousNestedBottomView.OnScrollNotifier() { @Override public void notify(int innerOffset, int innerRange) { - dispatchBottomScroll(-mBottomAreaBehavior.getTopAndBottomOffset(), ((View) mBottomView).getHeight(), + dispatchBottomScroll(-mBottomAreaBehavior.getTopAndBottomOffset(), getOffsetRange(), innerOffset, innerRange); } }); @@ -150,21 +158,23 @@ public class QMUIContinuousNestedScrollLayout extends CoordinatorLayout implemen int contentHeight = mBottomView.getContentHeight(); if (contentHeight != IQMUIContinuousNestedBottomView.HEIGHT_IS_ENOUGH_TO_SCROLL) { // bottomView can not scroll - mTopAreaBehavior.setTopAndBottomOffset(getHeight() - contentHeight - ((View) mTopView).getHeight()); + mTopAreaBehavior.setTopAndBottomOffset( + getHeight() - contentHeight - ((View) mTopView).getHeight()); return; } - mTopAreaBehavior.setTopAndBottomOffset(-((View) mTopView).getHeight()); + mTopAreaBehavior.setTopAndBottomOffset( + -((View) mTopView).getHeight() + getHeight() - ((View) mBottomView).getHeight()); } } } - public void scrollBy(int dy){ - if(dy > 0){ - if(mTopAreaBehavior != null){ - mTopAreaBehavior.scroll(this, ((View)mTopView), dy); + public void scrollBy(int dy) { + if (dy > 0) { + if (mTopAreaBehavior != null) { + mTopAreaBehavior.scroll(this, ((View) mTopView), dy); } - }else if(dy < 0){ - if(mBottomView != null){ + } else if (dy < 0) { + if (mBottomView != null) { mBottomView.consumeScroll(dy); } } @@ -189,10 +199,17 @@ public class QMUIContinuousNestedScrollLayout extends CoordinatorLayout implemen int contentHeight = mBottomView.getContentHeight(); if (contentHeight != IQMUIContinuousNestedBottomView.HEIGHT_IS_ENOUGH_TO_SCROLL) { // bottomView can not scroll - mTopAreaBehavior.setTopAndBottomOffset(getHeight() - contentHeight - ((View) mTopView).getHeight()); + View topView = (View) mTopView; + if (topView.getHeight() + contentHeight < getHeight()) { + mTopAreaBehavior.setTopAndBottomOffset(0); + } else { + mTopAreaBehavior.setTopAndBottomOffset( + getHeight() - contentHeight - ((View) mTopView).getHeight()); + } return; } - mTopAreaBehavior.setTopAndBottomOffset(-((View) mTopView).getHeight()); + mTopAreaBehavior.setTopAndBottomOffset( + -((View) mTopView).getHeight() + getHeight() - ((View) mBottomView).getHeight()); } } if (mBottomView != null) { @@ -200,22 +217,80 @@ public class QMUIContinuousNestedScrollLayout extends CoordinatorLayout implemen } } + private int getOffsetRange() { + if (mTopView == null || mBottomView == null) { + return 0; + } + int contentHeight = mBottomView.getContentHeight(); + if (contentHeight != IQMUIContinuousNestedBottomView.HEIGHT_IS_ENOUGH_TO_SCROLL) { + return ((View) mTopView).getHeight() - (getHeight() - contentHeight); + } + return ((View) mTopView).getHeight() - (getHeight() - ((View) mBottomView).getHeight()); + } + @Override public void notify(int innerOffset, int innerRange) { - dispatchTopScroll(-mTopAreaBehavior.getTopAndBottomOffset(), ((View) mTopView).getHeight(), + dispatchTopScroll(-mTopAreaBehavior.getTopAndBottomOffset(), getOffsetRange(), innerOffset, innerRange); } @Override public void onTopAreaOffset(int offset) { - dispatchTopScroll(-offset, ((View) mTopView).getHeight(), + dispatchTopScroll(-offset, getOffsetRange(), mTopView.getCurrentScroll(), mTopView.getScrollOffsetRange()); - dispatchBottomScroll(-offset, ((View)mBottomView).getHeight(), + dispatchBottomScroll(-offset, getOffsetRange(), mBottomView.getCurrentScroll(), mBottomView.getScrollOffsetRange()); } + public ScrollInfo saveScrollInfo() { + Object topInfo = mTopView != null ? mTopView.saveScrollInfo() : null; + Object bottomInfo = mBottomView != null ? mBottomView.saveScrollInfo() : null; + return new ScrollInfo(topInfo, bottomInfo, mTopAreaBehavior.getTopAndBottomOffset()); + } + + public void restoreScrollInfo(@Nullable ScrollInfo scrollInfo) { + if (scrollInfo == null) { + return; + } + if (mTopAreaBehavior != null) { + mTopAreaBehavior.setTopAndBottomOffset(scrollInfo.getTopBottomOffset()); + } + if (mTopView != null) { + mTopView.restoreScrollInfo(scrollInfo.topInfo); + } + + if (mBottomView != null) { + mBottomView.restoreScrollInfo(scrollInfo.bottomInfo); + } + } + public interface OnScrollListener { void onTopScroll(int offset, int range, int innerOffset, int innerRange); + void onBottomScroll(int offset, int range, int innerOffset, int innerRange); } + + public static class ScrollInfo { + private Object topInfo; + private Object bottomInfo; + private int topBottomOffset; + + public ScrollInfo(Object topInfo, Object bottomInfo, int topBottomOffset) { + this.topInfo = topInfo; + this.bottomInfo = bottomInfo; + this.topBottomOffset = topBottomOffset; + } + + public int getTopBottomOffset() { + return topBottomOffset; + } + + public Object getTopInfo() { + return topInfo; + } + + public Object getBottomInfo() { + return bottomInfo; + } + } } diff --git a/qmui/src/main/java/com/qmuiteam/qmui/nestedScroll/QMUIContinuousNestedTopAreaBehavior.java b/qmui/src/main/java/com/qmuiteam/qmui/nestedScroll/QMUIContinuousNestedTopAreaBehavior.java index 56c8b870..edbd4582 100644 --- a/qmui/src/main/java/com/qmuiteam/qmui/nestedScroll/QMUIContinuousNestedTopAreaBehavior.java +++ b/qmui/src/main/java/com/qmuiteam/qmui/nestedScroll/QMUIContinuousNestedTopAreaBehavior.java @@ -272,9 +272,11 @@ public class QMUIContinuousNestedTopAreaBehavior extends QMUIViewOffsetBehavior< // child is topView, target is bottomView if (target instanceof IQMUIContinuousNestedBottomView) { int contentHeight = ((IQMUIContinuousNestedBottomView) target).getContentHeight(); - int minOffset = -child.getHeight(); + int minOffset; if (contentHeight != IQMUIContinuousNestedBottomView.HEIGHT_IS_ENOUGH_TO_SCROLL) { minOffset = parent.getHeight() - contentHeight - child.getHeight(); + }else{ + minOffset = parent.getHeight() - child.getHeight() - target.getHeight(); } if (child.getTop() - dy >= minOffset) { setTopAndBottomOffset(child.getTop() - dy - getLayoutTop()); @@ -314,7 +316,7 @@ public class QMUIContinuousNestedTopAreaBehavior extends QMUIViewOffsetBehavior< int minBottom = parent.getHeight(); boolean canContentScroll = true; if (contentHeight != IQMUIContinuousNestedBottomView.HEIGHT_IS_ENOUGH_TO_SCROLL) { - minBottom = parent.getHeight() + parent.getHeight() - contentHeight; + minBottom = parent.getHeight() + bottomView.getHeight() - contentHeight; canContentScroll = false; } if (bottomView.getBottom() - minBottom > dyUnconsumed) { diff --git a/qmui/src/main/java/com/qmuiteam/qmui/nestedScroll/QMUIContinuousNestedTopDelegateLayout.java b/qmui/src/main/java/com/qmuiteam/qmui/nestedScroll/QMUIContinuousNestedTopDelegateLayout.java index 563143d2..013032b7 100644 --- a/qmui/src/main/java/com/qmuiteam/qmui/nestedScroll/QMUIContinuousNestedTopDelegateLayout.java +++ b/qmui/src/main/java/com/qmuiteam/qmui/nestedScroll/QMUIContinuousNestedTopDelegateLayout.java @@ -62,6 +62,7 @@ public class QMUIContinuousNestedTopDelegateLayout extends FrameLayout implement mChildHelper = new NestedScrollingChildHelper(this); ViewCompat.setNestedScrollingEnabled(this, true); + setClipToPadding(false); } public void setHeaderView(@NonNull View headerView) { @@ -92,30 +93,36 @@ public class QMUIContinuousNestedTopDelegateLayout extends FrameLayout implement @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, heightMeasureSpec); int w = MeasureSpec.getSize(widthMeasureSpec); int h = MeasureSpec.getSize(heightMeasureSpec); - int anchorHeight = 0; + int anchorHeight = getPaddingTop(); if (mHeaderView != null) { + mHeaderView.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(h, MeasureSpec.AT_MOST)); anchorHeight += mHeaderView.getMeasuredHeight(); } if (mDelegateView != null) { View delegateView = (View) mDelegateView; + delegateView.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(h, MeasureSpec.AT_MOST)); anchorHeight += delegateView.getMeasuredHeight(); } if (mFooterView != null) { + mFooterView.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(h, MeasureSpec.AT_MOST)); anchorHeight += mFooterView.getMeasuredHeight(); } + + anchorHeight += getPaddingBottom(); if (anchorHeight < h) { setMeasuredDimension(w, anchorHeight); + } else { + setMeasuredDimension(w, h); } } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { int w = right - left, h = bottom - top; - int anchorTop = 0; + int anchorTop = getPaddingTop(); int viewHeight; if (mHeaderView != null) { viewHeight = mHeaderView.getMeasuredHeight(); @@ -135,6 +142,7 @@ public class QMUIContinuousNestedTopDelegateLayout extends FrameLayout implement mFooterView.layout(0, anchorTop, w, anchorTop + viewHeight); anchorTop += viewHeight; } + anchorTop += getPaddingBottom(); mOffsetRange = Math.max(0, anchorTop - h); @@ -195,7 +203,7 @@ public class QMUIContinuousNestedTopDelegateLayout extends FrameLayout implement } return dyUnconsumed; } else { - int beforeRange = mHeaderView == null ? 0 : mHeaderView.getHeight(); + int beforeRange = getPaddingTop() + (mHeaderView == null ? 0 : mHeaderView.getHeight()); if (dyUnconsumed == Integer.MAX_VALUE) { offsetTo(beforeRange); } else if (mOffsetCurrent + dyUnconsumed <= beforeRange) { @@ -233,7 +241,7 @@ public class QMUIContinuousNestedTopDelegateLayout extends FrameLayout implement } return dyUnconsumed; } - int afterRange = mOffsetRange - (mFooterView == null ? 0 : mFooterView.getHeight()); + int afterRange = mOffsetRange - getPaddingBottom() - (mFooterView == null ? 0 : mFooterView.getHeight()); if (dyUnconsumed == Integer.MIN_VALUE) { offsetTo(afterRange); } else if (mOffsetCurrent + dyUnconsumed > afterRange) { @@ -291,6 +299,41 @@ public class QMUIContinuousNestedTopDelegateLayout extends FrameLayout implement } } + @Override + public Object saveScrollInfo() { + return new ScrollInfo(-mOffsetCurrent, mDelegateView == null ? null : mDelegateView.saveScrollInfo()); + } + + @Override + public void restoreScrollInfo(Object scrollInfo) { + if (scrollInfo instanceof ScrollInfo) { + ScrollInfo si = (ScrollInfo) scrollInfo; + if (mHeaderViewOffsetHelper != null) { + mHeaderViewOffsetHelper.setTopAndBottomOffset(si.topBottomOffset); + } + if (mDelegateViewOffsetHelper != null) { + mDelegateViewOffsetHelper.setTopAndBottomOffset(si.topBottomOffset); + } + if (mFooterViewOffsetHelper != null) { + mFooterViewOffsetHelper.setTopAndBottomOffset(si.topBottomOffset); + } + + if (mDelegateView != null) { + mDelegateView.restoreScrollInfo(((ScrollInfo) scrollInfo).delegateScrollInfo); + } + } + } + + public static class ScrollInfo { + int topBottomOffset; + Object delegateScrollInfo; + + public ScrollInfo(int topBottomOffset, Object delegateScrollInfo) { + this.topBottomOffset = topBottomOffset; + this.delegateScrollInfo = delegateScrollInfo; + } + } + // NestedScrollingChild2 @Override @@ -395,7 +438,7 @@ public class QMUIContinuousNestedTopDelegateLayout extends FrameLayout implement public void onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int type) { int consumed = 0; - if (dyUnconsumed > 0 && mFooterView != null) { + if (dyUnconsumed > 0) { if (mOffsetCurrent + dyUnconsumed <= mOffsetRange) { consumed = dyUnconsumed; offsetTo(mOffsetCurrent + dyUnconsumed); @@ -403,7 +446,7 @@ public class QMUIContinuousNestedTopDelegateLayout extends FrameLayout implement consumed = mOffsetRange - mOffsetCurrent; offsetTo(mOffsetRange); } - } else if (dyUnconsumed < 0 && mHeaderView != null) { + } else if (dyUnconsumed < 0) { if (mOffsetCurrent + dyUnconsumed >= 0) { consumed = dyUnconsumed; offsetTo(mOffsetCurrent + dyUnconsumed); @@ -421,16 +464,17 @@ public class QMUIContinuousNestedTopDelegateLayout extends FrameLayout implement int type) { dispatchNestedPreScroll(dx, dy, consumed, null, type); int unconsumed = dy - consumed[1]; - if (unconsumed > 0 && mHeaderView != null) { - if (mOffsetCurrent + unconsumed <= mHeaderView.getHeight()) { + if (unconsumed > 0) { + int topMargin = getPaddingTop() + (mHeaderView == null ? 0 : mHeaderView.getHeight()); + if (mOffsetCurrent + unconsumed <= topMargin) { offsetTo(mOffsetCurrent + unconsumed); consumed[1] += unconsumed; - } else if (mOffsetCurrent < mHeaderView.getHeight()) { - consumed[1] += mHeaderView.getHeight() - mOffsetCurrent; - offsetTo(mHeaderView.getHeight()); + } else if (mOffsetCurrent < topMargin) { + consumed[1] += topMargin - mOffsetCurrent; + offsetTo(topMargin); } - } else if (unconsumed < 0 && mFooterView != null) { - int b = mOffsetRange - mFooterView.getHeight(); + } else if (unconsumed < 0) { + int b = mOffsetRange - getPaddingBottom() - (mFooterView != null ? mFooterView.getHeight() : 0); if (mOffsetCurrent + unconsumed >= b) { offsetTo(mOffsetCurrent + unconsumed); consumed[1] += unconsumed; diff --git a/qmui/src/main/java/com/qmuiteam/qmui/nestedScroll/QMUIContinuousNestedTopLinearLayout.java b/qmui/src/main/java/com/qmuiteam/qmui/nestedScroll/QMUIContinuousNestedTopLinearLayout.java index 0846ed95..3a72ca82 100644 --- a/qmui/src/main/java/com/qmuiteam/qmui/nestedScroll/QMUIContinuousNestedTopLinearLayout.java +++ b/qmui/src/main/java/com/qmuiteam/qmui/nestedScroll/QMUIContinuousNestedTopLinearLayout.java @@ -56,4 +56,14 @@ public class QMUIContinuousNestedTopLinearLayout extends QMUILinearLayout implem public void injectScrollNotifier(OnScrollNotifier notifier) { } + + @Override + public void restoreScrollInfo(Object scrollInfo) { + + } + + @Override + public Object saveScrollInfo() { + return null; + } } diff --git a/qmui/src/main/java/com/qmuiteam/qmui/nestedScroll/QMUIContinuousNestedTopRecyclerView.java b/qmui/src/main/java/com/qmuiteam/qmui/nestedScroll/QMUIContinuousNestedTopRecyclerView.java index 6593b013..9d394a3e 100644 --- a/qmui/src/main/java/com/qmuiteam/qmui/nestedScroll/QMUIContinuousNestedTopRecyclerView.java +++ b/qmui/src/main/java/com/qmuiteam/qmui/nestedScroll/QMUIContinuousNestedTopRecyclerView.java @@ -20,8 +20,10 @@ import android.content.Context; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.view.ViewCompat; +import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.util.AttributeSet; +import android.view.View; public class QMUIContinuousNestedTopRecyclerView extends RecyclerView implements IQMUIContinuousNestedTopView { @@ -92,4 +94,42 @@ public class QMUIContinuousNestedTopRecyclerView extends RecyclerView implements super.onScrolled(dx, dy); mScrollNotifier.notify(getCurrentScroll(), getScrollOffsetRange()); } + + @Override + public Object saveScrollInfo() { + LayoutManager layoutManager = getLayoutManager(); + if (layoutManager instanceof LinearLayoutManager) { + LinearLayoutManager lm = (LinearLayoutManager) layoutManager; + if (lm.getOrientation() == LinearLayoutManager.HORIZONTAL) { + return null; + } + int pos = lm.findFirstVisibleItemPosition(); + View firstView = lm.findViewByPosition(pos); + int offset = firstView == null ? 0 : firstView.getTop(); + return new ScrollInfo(pos, offset); + } + return null; + } + + @Override + public void restoreScrollInfo(Object scrollInfo) { + if (!(scrollInfo instanceof ScrollInfo)) { + return; + } + ScrollInfo sc = (ScrollInfo) scrollInfo; + LayoutManager layoutManager = getLayoutManager(); + if (layoutManager instanceof LinearLayoutManager) { + ((LinearLayoutManager) layoutManager).scrollToPositionWithOffset(sc.scrollPosition, sc.scrollOffset); + } + } + + public static class ScrollInfo { + int scrollPosition; + int scrollOffset; + + public ScrollInfo(int scrollPosition, int scrollOffset) { + this.scrollPosition = scrollPosition; + this.scrollOffset = scrollOffset; + } + } } diff --git a/qmui/src/main/java/com/qmuiteam/qmui/nestedScroll/QMUIContinuousNestedTopWebView.java b/qmui/src/main/java/com/qmuiteam/qmui/nestedScroll/QMUIContinuousNestedTopWebView.java index 3647853e..bf7b1511 100644 --- a/qmui/src/main/java/com/qmuiteam/qmui/nestedScroll/QMUIContinuousNestedTopWebView.java +++ b/qmui/src/main/java/com/qmuiteam/qmui/nestedScroll/QMUIContinuousNestedTopWebView.java @@ -78,4 +78,16 @@ public class QMUIContinuousNestedTopWebView extends QMUIWebView implements IQMUI mScrollNotifier.notify(getCurrentScroll(), getScrollOffsetRange()); } } + + @Override + public Object saveScrollInfo() { + return getScrollY(); + } + + @Override + public void restoreScrollInfo(Object scrollInfo) { + if (scrollInfo instanceof Integer) { + scrollTo(0, (Integer) scrollInfo); + } + } } diff --git a/qmuidemo/src/main/java/com/qmuiteam/qmuidemo/fragment/lab/QDContinuousBottomView.java b/qmuidemo/src/main/java/com/qmuiteam/qmuidemo/fragment/lab/QDContinuousBottomView.java index d341dffe..6750d39e 100644 --- a/qmuidemo/src/main/java/com/qmuiteam/qmuidemo/fragment/lab/QDContinuousBottomView.java +++ b/qmuidemo/src/main/java/com/qmuiteam/qmuidemo/fragment/lab/QDContinuousBottomView.java @@ -46,6 +46,7 @@ public class QDContinuousBottomView extends QMUIContinuousNestedBottomDelegateLa private MyViewPager mViewPager; private QMUIContinuousNestedBottomRecyclerView mCurrentItemView; + private int mCurrentPosition = -1; private IQMUIContinuousNestedBottomView.OnScrollNotifier mOnScrollNotifier; public QDContinuousBottomView(Context context) { @@ -146,6 +147,7 @@ public class QDContinuousBottomView extends QMUIContinuousNestedBottomDelegateLa public void setPrimaryItem(@NonNull ViewGroup container, int position, @NonNull Object object) { super.setPrimaryItem(container, position, object); mCurrentItemView = (QMUIContinuousNestedBottomRecyclerView) object; + mCurrentPosition = position; if (mOnScrollNotifier != null) { mCurrentItemView.injectScrollNotifier(mOnScrollNotifier); } @@ -208,5 +210,33 @@ public class QDContinuousBottomView extends QMUIContinuousNestedBottomDelegateLa mCurrentItemView.injectScrollNotifier(notifier); } } + + @Override + public Object saveScrollInfo() { + if (mCurrentItemView != null) { + return new ScrollInfo(mCurrentPosition, mCurrentItemView.saveScrollInfo()); + } + return null; + } + + @Override + public void restoreScrollInfo(Object scrollInfo) { + if (mCurrentItemView != null && (scrollInfo instanceof ScrollInfo)) { + ScrollInfo si = (ScrollInfo) scrollInfo; + if (si.currentPosition == mCurrentPosition) { + mCurrentItemView.restoreScrollInfo(si.currentScrollInfo); + } + } + } + + class ScrollInfo { + int currentPosition; + Object currentScrollInfo; + + public ScrollInfo(int currentPosition, Object currentScrollInfo) { + this.currentPosition = currentPosition; + this.currentScrollInfo = currentScrollInfo; + } + } } } \ No newline at end of file