我在CardView
父级内部有可扩展的视图NestedScrollView
。当展开动画结束时,我正在尝试为子项创建平滑滚动。但我只找到了一种解决方案:
scrollView.requestChildFocus(someView, someView);
这段代码工作正常,但是,当调用requestChildFocus
它时,它会立即滚动,这让我有点恼火。是否可以顺利滚动到孩子?
我在CardView
父级内部有可扩展的视图NestedScrollView
。当展开动画结束时,我正在尝试为子项创建平滑滚动。但我只找到了一种解决方案:
scrollView.requestChildFocus(someView, someView);
这段代码工作正常,但是,当调用requestChildFocus
它时,它会立即滚动,这让我有点恼火。是否可以顺利滚动到孩子?
childView
我想滚动到的 , 具有父CardView
级,因此childView.getTop()
将相对于CardView
not 的值返回给ScrollView
. 因此,要获得相对于我的最高水平,ScrollView
我应该childView.getParent().getParent()
将其转换为View
并调用getTop()
.
滚动位置计算如下
int scrollTo = ((View) childView.getParent().getParent()).getTop() + childView.getTop();
nestedScrollView.smoothScrollTo(0, scrollTo);
更多来自@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)
}
我有不同级别的子视图到滚动视图,所以根据接受的答案制作了这个函数来计算距离和滚动
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);
你可以使用我的图书馆ViewPropertyObjectAnimator
。
假设mNestedScrollView
是您的NestedScrollView
并且是您要滚动到mChildView
的孩子,您可以执行以下操作:View
ViewPropertyObjectAnimator.animate(mNestedScrollView).scrollY(mChildView.getTop()).start();
只要确保mChildView.getTop()
不是0
在调用的那一刻.animate(...)
。
编辑:
正如我所说:确保View's
CALL 时您的顶部不为零.animate(...)
。换句话说:.animate(...)
只有当您的孩子View
已经有了尺寸时才打电话。你怎么能确定呢?例如像这样:
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();
}
}
});
尝试阅读源代码。
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
是您希望在屏幕上显示视图的地方。
这应该可以完成工作,其中 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);
}
我发现公认的答案是可行的,但它目前特定于他们的视图结构,它不能用作静态方法来用于具有不同视图结构的所有类似滚动。我在一个实用程序类中制作了各种它,直到它发现它是 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);
}
});
}
主要问题是计算相对于嵌套滚动视图的正确 x/y 位置。但是,这里的大多数答案都试图通过在层次结构中导航并硬编码所需视图的层次结构级别来提出解决方案。恕我直言,如果您更改视图组层次结构,这很容易出错。
因此,我建议使用更简洁的方法,它基于 a 计算相对位置Rect
。然后,您可以使用nestedscrollview 的smoothScrollTo(..)方法滚动到所需位置。