web-dev-qa-db-ja.com

NestedScrollViewで子にスムージースクロール

親がCardViewであるNestedScrollView内に拡張可能なビューがあります。展開アニメーションが終了したときに子へのスムーズなスクロールを作成しようとしています。しかし、私はただ1つの解決策を見つけました:

 scrollView.requestChildFocus(someView, someView);

このコードは正常に機能しますが、requestChildFocusを呼び出すとすぐにスクロールするため、少し面倒です。子までスムーズにスクロールできますか?

13
Near1999

スクロールしたいchildViewにはCardView parrentがあるため、childView.getTop()CardViewではなくScrollViewに関連する値を返します。 var] _。したがって、ScrollViewに対してトップを取得するには、childView.getParent().getParent()を取得し、それをViewにキャストして、getTop()を呼び出す必要があります。

スクロール位置は次のように計算されます

int scrollTo = ((View) childView.getParent().getParent()).getTop() + childView.getTop();
nestedScrollView.smoothScrollTo(0, scrollTo);
17
Near1999

あなたは私のライブラリを使うことができます ViewPropertyObjectAnimator そのために。

mNestedScrollViewNestedScrollViewであり、mChildViewがスクロール先の子Viewであるとすると、次のことができます。

_ViewPropertyObjectAnimator.animate(mNestedScrollView).scrollY(mChildView.getTop()).start();
_

mChildView.getTop()を呼び出すときに、.animate(...)が_0_でないことを確認してください。

編集:

私が言ったように:CALL .animate(...)のときは、_View's_トップがゼロ以外であることを確認してください。言い換えると、子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();
        }
    }
});
_
1
Bartek Lipinski

ソースコードを読んでみてください。

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は、ビューを画面に表示する場所です。

0
tiny sunlight

@ 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)
}
0
CHAN

これで作業が完了します。ここで、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);
    }
0
Jitheesh S Khan

スクロールビューとは異なるレベルの子ビューがあったので、受け入れられた回答に基づいてこの関数を作成し、距離とスクロールを計算しました

  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("scrollview not found");
    return 0;
}

次に、を使用してスクロールします

journal_scrollview.smoothScrollTo(0, distance);
0
Jerry Sha