我在NestedScrollView
中有一个可展开的视图,它的父项是CardView
。当展开动画结束后,我想要创建平滑的滚动到子项。但我只找到了一种解决方案:
scrollView.requestChildFocus(someView, someView);
这段代码运行良好,但是当调用requestChildFocus
时它会立即滚动,这让我有点烦。是否有可能平滑地滚动到子元素?
我在NestedScrollView
中有一个可展开的视图,它的父项是CardView
。当展开动画结束后,我想要创建平滑的滚动到子项。但我只找到了一种解决方案:
scrollView.requestChildFocus(someView, someView);
这段代码运行良好,但是当调用requestChildFocus
时它会立即滚动,这让我有点烦。是否有可能平滑地滚动到子元素?
我想滚动到的childView
有一个父级CardView
,因此childView.getTop()
返回相对于CardView
而不是ScrollView
的值。 因此,要获取相对于ScrollView
的顶部,我应该获取childView.getParent().getParent()
并将其强制转换为View
,然后调用getTop()
。
滚动位置的计算方式如下:
int scrollTo = ((View) childView.getParent().getParent()).getTop() + childView.getTop();
nestedScrollView.smoothScrollTo(0, scrollTo);
nestedScrollView.smoothScrollTo
对我来说根本不起作用(Support lib 27.1.1) - Konstantin Konopko接下来是 @jerry-sha 的更多回答
fun NestedScrollView.smoothScrollTo(view: View) {
var distance = view.top
var viewParent = view.parent
//traverses 10 times
for (i in 0..9) {
if ((viewParent as View) === this) break
distance += (viewParent as View).top
viewParent = viewParent.getParent()
}
smoothScrollTo(0, distance)
}
我在scrollview的不同级别中有子视图,因此基于已接受的答案编写了这个函数来计算距离和滚动。
private int findDistanceToScroll(View view){
int distance = view.getTop();
ViewParent viewParent = view.getParent();
//traverses 10 times
for(int i = 0; i < 10; i++) {
if (((View) viewParent).getId() == R.id.journal_scrollview) {
return distance;
}
distance += ((View) viewParent).getTop();
viewParent = viewParent.getParent();
}
Timber.w("view not found");
return 0;
}
journal_scrollview.smoothScrollTo(0, distance);
svMain.setSmoothScrollingEnabled(true);
Rect rect = new Rect();
rect.top = 0;
rect.left = 0;
rect.right = tv4.getWidth();
rect.bottom =tv4.getHeight();
svMain.requestChildRectangleOnScreen(tv4,rect,false);
rect
是您希望在屏幕上显示视图的位置。
你可以使用我的库ViewPropertyObjectAnimator
来完成这个功能。
假设mNestedScrollView
是你的NestedScrollView
,mChildView
是你想要滚动到的子View
,你可以按照以下步骤操作:
ViewPropertyObjectAnimator.animate(mNestedScrollView).scrollY(mChildView.getTop()).start();
.animate(...)
时,mChildView.getTop()
不为 0
。
编辑:
如我所说:在调用 .animate(...)
时,请确保您的 View
顶部不为零。换句话说,只有当您的子 View
已经具有尺寸时才调用 .animate(...)
。您怎样才能确定这一点?例如像这样:
mChildView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
int width = mChildView.getWidth();
int height = mChildView.getHeight();
if (width > 0 && height > 0) {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) {
mChildView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
} else {
mChildView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
ViewPropertyObjectAnimator.animate(mNestedScrollView)
.scrollY(mChildView.getTop())
.start();
}
}
});
mChildView.getTop()
表示从您的 View
顶部到 NestedScrollView
内容顶部的像素数。这个命令将精确滚动您的 NestedScrollView
到这个位置。 - Bartek LipinskiRect
计算相对位置。然后,您可以使用嵌套滚动视图的smoothScrollTo(..)方法滚动到所需位置。我发现已被接受的答案可行,但它仅适用于当前他们的视图结构,并且不能用作对所有具有不同视图结构的类似滚动的静态方法。我在一个实用程序类中制作了它的多个版本,直到它找到它的ScrollView或NestedScrollView父项为止。我使它可以使用scrollToView(View,View)方法来处理ScrollView和NestedScrollView,以防以后更新我使用的内容或其他情况。当然,您也可以直接调用正确的“子方法”。
public static void scrollToView(View scrollView, View scrollToView) {
if (scrollToView == null) {
Log.d(TAG, "scrollToView() failed due to scrollToView == NULL!");
return;
}
if (scrollView instanceof NestedScrollView) {
scrollToInNestedView((NestedScrollView) scrollView, scrollToView);
} else if (scrollView instanceof ScrollView) {
scrollToInScrollView((ScrollView) scrollView, scrollToView);
} else {
Log.d(TAG, "scrollToView() failed due to scrollView not appearing to be any kind of scroll view!");
}
}
public static void scrollToInNestedView(NestedScrollView scrollView, View scrollToView) {
if (scrollView == null || scrollToView == null) {
return;
}
scrollView.post(() -> {
int startY = scrollView.getScrollY();
int requiredY = scrollToView.getTop();
View parent = (View) scrollToView.getParent();
while (parent != null && !(parent instanceof NestedScrollView)) {
requiredY += parent.getTop();
parent = (View) parent.getParent();
}
if (requiredY != startY) {
scrollView.smoothScrollTo(0, requiredY);
}
});
}
public static void scrollToInScrollView(ScrollView scrollView, View scrollToView) {
if (scrollView == null || scrollToView == null) {
return;
}
scrollView.post(() -> {
int startY = scrollView.getScrollY();
int requiredY = scrollToView.getTop();
View parent = (View) scrollToView.getParent();
while (parent != null && !(parent instanceof ScrollView)) {
requiredY += parent.getTop();
parent = (View) parent.getParent();
}
if (requiredY != startY) {
scrollView.smoothScrollTo(0, requiredY);
}
});
}
这应该可以完成工作,其中childView是您想要滚动到的视图
public static void scrollToView(final NestedScrollView nestedScrollView, final View viewToScrollTo) {
final int[] xYPos = new int[2];
viewToScrollTo.getLocationOnScreen(xYPos);
final int[] scrollxYPos = new int[2];
nestedScrollView.getLocationOnScreen(scrollxYPos);
int yPosition = xYPos[1];
if (yPosition < 0) {
yPosition = 0;
}
nestedScrollView.scrollTo(0, scrollxYPos[1] - yPosition);
}