プログラムでスクロールビューを特定の編集テキストにスクロールする方法はありますか?


206

スクロールビューで非常に長いアクティビティがあります。これは、ユーザーが入力する必要のあるさまざまなフィールドを持つフォームです。フォームの下半分にチェックボックスがあり、ユーザーがチェックすると、ビューの特定の部分にスクロールします。EditTextオブジェクト(または他のビューオブジェクト)にプログラムでスクロールする方法はありますか?

また、X座標とY座標を使用してこれが可能であることはわかっていますが、フォームがユーザーごとに変更される可能性があるため、これを回避したいと思います。


3
the form may changed from user to userしかし、あなたはそのまま使うことができますmEditView.getTop();
nebkat

1
CoordinatorLayout内でNestedScrollViewを使用している場合は、stackoverflow.com
questions / 52083678 /…

回答:


451
private final void focusOnView(){
        your_scrollview.post(new Runnable() {
            @Override
            public void run() {
                your_scrollview.scrollTo(0, your_EditBox.getBottom());
            }
        });
    }

129
私は、smoothScrollTo(0、your_EditBox.getTop())を使用するとより良い結果が得られることを発見しました(目的のビューへのスクロールがスムーズになります)が、それ以外-素晴らしい答えです。
ムジカント2012

18
@ xmenW.K。短い答え:UIは一連の処理に基づいて作業を行い、基本的にUIスレッドに指示しているので、できる場合は、今までにやらなければならないことをすべて実行した後、これを実行します(スクロール) 。基本的には、スクロールをキューに入れ、スレッドが可能なときにそれを実行できるようにし、要求する前に行っていた処理の順序を尊重します。
Martin Marconcini、2014

37
新しいハンドラをインスタンス化するのではなく、ScrollView自体へのRunnableを投稿することも可能である:your_scrollview.post(...
シェリフelKhatib

getBottom()ではなくビューの中心を取得するメソッドはありますか?私の場合はEditTextではなくgoogleMapです。
Zin Win Htet

5
getBottom()とgetTop()は親を基準にしています
雑多な

57

ビューをスクロールビューの中央スクロールする場合は、Sherif elKhatibの答えを大幅に改善できます。この再利用可能なメソッドは、Horizo​​ntalScrollViewの可視の中心までビューをスムーズにスクロールします。

private final void focusOnView(final HorizontalScrollView scroll, final View view) {
    new Handler().post(new Runnable() {
        @Override
        public void run() {
            int vLeft = view.getLeft();
            int vRight = view.getRight();
            int sWidth = scroll.getWidth();
            scroll.smoothScrollTo(((vLeft + vRight - sWidth) / 2), 0);
        }
    });
}

縦置きScrollView

...
int vTop = view.getTop();
int vBottom = view.getBottom();
int sHeight = scroll.getBottom();
scroll.smoothScrollTo(((vTop + vBottom - sHeight) / 2), 0);
...

3
コードを調整する必要があります。スクロールビューの幅を取得し、式をsv.smoothScrollTo(((vLeft + vRight)/ 2)-(svWidth / 2)、0);に変更する必要があります。
小学校の

2
そうしないと、scrollViewのビューが中央に配置されません。私はすでにあなたのために編集をしました。
小学校

古い方がうまく機能していたので、式が正確に機能しているか確認しましたか
ahmadalibaloch

1
@Elementary Yoursとahmadsの数式は、同じ代数式の簡略版と拡張版であり、調整の必要はありません。
k29、2015

1
@ k29ここで目に見える2つの式を参照していますか?どちらも私からのものです。コメントの式をさらに簡略化し、それに応じて回答を編集しました。しかし、残りはすべて元の回答と同じであり、私にとっても非常に役に立ちました。
小学校、

51

これは私にとってうまくいきます:

  targetView.getParent().requestChildFocus(targetView,targetView);

public void RequestChildFocus(子を表示、フォーカスを表示)

-フォーカスを望んでいる。このViewParentの子。このビューには、フォーカスされたビューが含まれます。実際にフォーカスがあるのは、必ずしもビューではありません。

フォーカスされた -実際にフォーカスがある子供の子孫であるビュー


スムーズスクロールでジャンプの種類を表示
silentsudo 2018

32

私の考えでは、特定の長方形にスクロールする最良の方法は、を使用することView.requestRectangleOnScreen(Rect, Boolean)です。Viewスクロールしたい場所でそれを呼び出し、画面に表示したいローカル長方形を渡す必要があります。2番目のパラメーターはfalse、スムーズスクロールとtrue即時スクロールのためのものです。

final Rect rect = new Rect(0, 0, view.getWidth(), view.getHeight());
view.requestRectangleOnScreen(rect, false);

1
私のためにビューページャー内で働いたscrollviewがあり、ここで言及されているコードを使用して現在機能しているビューにスクロールする必要があります。
Pankaj

2
間違いなくこれは受け入れられる答えであるはずscrollview.smoothScrollToです。必要なビューが画面外にある場合は機能しません(SDKバージョン26のAndroidエミュレーターで試してみました)
Sony

@Michaelラップする必要がありnew Handler().post()ますか?
ジョニーファイブ

@JohnnyFiveこのコードを使用するコンテキストによって異なります。
マイケル

12

WarrenFaithからの回答に基づいて小さなユーティリティメソッドを作成しました。このコードは、そのビューが既にscrollviewに表示されていて、スクロールする必要がない場合にも考慮します。

public static void scrollToView(final ScrollView scrollView, final View view) {

    // View needs a focus
    view.requestFocus();

    // Determine if scroll needs to happen
    final Rect scrollBounds = new Rect();
    scrollView.getHitRect(scrollBounds);
    if (!view.getLocalVisibleRect(scrollBounds)) {
        new Handler().post(new Runnable() {
            @Override
            public void run() {
                scrollView.smoothScrollTo(0, view.getBottom());
            }
        });
    } 
}

メソッドscrollBoundsのパラメーターになると思いますscrollView.getHitRect
Vijay C


7

EditTextはScrollView内にいくつかのレイヤーをネストしましたが、それ自体はレイアウトのルートビューではありません。getTop()とgetBottom()は、それを含むビュー内の座標を報告しているようだったので、EditTextの親を反復処理することによって、ScrollViewの上部からEditTextの上部までの距離を計算させました。

// Scroll the view so that the touched editText is near the top of the scroll view
new Thread(new Runnable()
{
    @Override
    public
    void run ()
    {
        // Make it feel like a two step process
        Utils.sleep(333);

        // Determine where to set the scroll-to to by measuring the distance from the top of the scroll view
        // to the control to focus on by summing the "top" position of each view in the hierarchy.
        int yDistanceToControlsView = 0;
        View parentView = (View) m_editTextControl.getParent();
        while (true)
        {
            if (parentView.equals(scrollView))
            {
                break;
            }
            yDistanceToControlsView += parentView.getTop();
            parentView = (View) parentView.getParent();
        }

        // Compute the final position value for the top and bottom of the control in the scroll view.
        final int topInScrollView = yDistanceToControlsView + m_editTextControl.getTop();
        final int bottomInScrollView = yDistanceToControlsView + m_editTextControl.getBottom();

        // Post the scroll action to happen on the scrollView with the UI thread.
        scrollView.post(new Runnable()
        {
            @Override
            public void run()
            {
                int height =m_editTextControl.getHeight();
                scrollView.smoothScrollTo(0, ((topInScrollView + bottomInScrollView) / 2) - height);
                m_editTextControl.requestFocus();
            }
        });
    }
}).start();

5

別のバリエーションは次のとおりです。

scrollView.postDelayed(new Runnable()
{
    @Override
    public void run()
    {
        scrollView.smoothScrollTo(0, img_transparent.getTop());
    }
}, 2000);

または、post()メソッドを使用できます。


5

私はこれがより良い答えには遅すぎるかもしれないことを知っていますが、望ましい完璧な解決策はポジショナーのようなシステムでなければなりません。つまり、システムがエディターフィールドの配置を行うとき、フィールドはキーボードのすぐ上に配置されるため、UI / UXのルールとしては完璧です。

以下のコードが作成するのは、Androidによるスムーズなポジショニングです。まず、現在のスクロールポイントを参照ポイントとして保持します。2つ目は、エディターに最適な配置のスクロールポイントを見つけることです。これを行うには、上にスクロールし、エディターフィールドに要求して、ScrollViewコンポーネントが最適な配置を行うようにします。ガッチャ!私たちは最高のポジションを学びました。次に、前のポイントから新しく見つけたポイントまでスムーズにスクロールします。必要に応じて、smoothScrollToの代わりにscrollToを使用して、スムーズスクロールを省略できます。

注:メインコンテナーScrollViewは、scrollViewSignupという名前のメンバーフィールドです。これは、多くのことを理解している可能性があるため、私の例はサインアップ画面であるためです。

view.setOnFocusChangeListener(new View.OnFocusChangeListener() {
        @Override
        public void onFocusChange(final View view, boolean b) {
            if (b) {
                scrollViewSignup.post(new Runnable() {
                    @Override
                    public void run() {
                        int scrollY = scrollViewSignup.getScrollY();
                        scrollViewSignup.scrollTo(0, 0);
                        final Rect rect = new Rect(0, 0, view.getWidth(), view.getHeight());
                        view.requestRectangleOnScreen(rect, true);

                        int new_scrollY = scrollViewSignup.getScrollY();
                        scrollViewSignup.scrollTo(0, scrollY);
                        scrollViewSignup.smoothScrollTo(0, new_scrollY);
                    }
                });
            }
        }
    });

このブロックをすべてのEditTextインスタンスに使用し、画面コードにすばやく統合する場合。以下のようなトラバーサーを作成するだけです。これを行うには、私がメインOnFocusChangeListenerという名前のメンバフィールド作ったfocusChangeListenerToScrollEditor、および以下のようにのonCreate中にそれを呼び出します。

traverseEditTextChildren(scrollViewSignup, focusChangeListenerToScrollEditor);

そして、メソッドの実装は以下の通りです。

private void traverseEditTextChildren(ViewGroup viewGroup, View.OnFocusChangeListener focusChangeListenerToScrollEditor) {
    int childCount = viewGroup.getChildCount();
    for (int i = 0; i < childCount; i++) {
        View view = viewGroup.getChildAt(i);
        if (view instanceof EditText)
        {
            ((EditText) view).setOnFocusChangeListener(focusChangeListenerToScrollEditor);
        }
        else if (view instanceof ViewGroup)
        {
            traverseEditTextChildren((ViewGroup) view, focusChangeListenerToScrollEditor);
        }
    }
}

したがって、ここで行ったことは、すべてのEditTextインスタンスを子にして、フォーカスのあるリスナーを呼び出すことです。

このソリューションに到達するために、ここですべてのソリューションをチェックアウトし、UI / UXの結果を改善するための新しいソリューションを生成しました。

他のすべての回答に感謝します。

3

ScrollViewがChildViewの直接の親である場合、上記の回答は正常に機能します。ChildViewがScrollViewの別のViewGroupにラップされている場合、View.getTop()がその親に対する相対位置を取得するため、予期しない動作が発生します。そのような場合、これを実装する必要があります:

public static void scrollToInvalidInputView(ScrollView scrollView, View view) {
    int vTop = view.getTop();

    while (!(view.getParent() instanceof ScrollView)) {
        view = (View) view.getParent();
        vTop += view.getTop();
    }

    final int scrollPosition = vTop;

    new Handler().post(() -> scrollView.smoothScrollTo(0, scrollPosition));
}

これは親の立場も考慮に入れるため、最も包括的なソリューションです。投稿ありがとうございます!
Gustavo Baiocchi Costa


2

私はよりエレガントでエラーが起こりにくい解決策を見つけたと思います

ScrollView.requestChildRectangleOnScreen

数学は含まれておらず、他の提案されたソリューションとは異なり、上下に正しくスクロールします。

/**
 * Will scroll the {@code scrollView} to make {@code viewToScroll} visible
 * 
 * @param scrollView parent of {@code scrollableContent}
 * @param scrollableContent a child of {@code scrollView} whitch holds the scrollable content (fills the viewport).
 * @param viewToScroll a child of {@code scrollableContent} to whitch will scroll the the {@code scrollView}
 */
void scrollToView(ScrollView scrollView, ViewGroup scrollableContent, View viewToScroll) {
    Rect viewToScrollRect = new Rect(); //coordinates to scroll to
    viewToScroll.getHitRect(viewToScrollRect); //fills viewToScrollRect with coordinates of viewToScroll relative to its parent (LinearLayout) 
    scrollView.requestChildRectangleOnScreen(scrollableContent, viewToScrollRect, false); //ScrollView will make sure, the given viewToScrollRect is visible
}

現時点で変更されているpostDelayed場合に備えて、それをラップして信頼性を高めることをお勧めしScrollViewます。

/**
 * Will scroll the {@code scrollView} to make {@code viewToScroll} visible
 * 
 * @param scrollView parent of {@code scrollableContent}
 * @param scrollableContent a child of {@code scrollView} whitch holds the scrollable content (fills the viewport).
 * @param viewToScroll a child of {@code scrollableContent} to whitch will scroll the the {@code scrollView}
 */
private void scrollToView(final ScrollView scrollView, final ViewGroup scrollableContent, final View viewToScroll) {
    long delay = 100; //delay to let finish with possible modifications to ScrollView
    scrollView.postDelayed(new Runnable() {
        public void run() {
            Rect viewToScrollRect = new Rect(); //coordinates to scroll to
            viewToScroll.getHitRect(viewToScrollRect); //fills viewToScrollRect with coordinates of viewToScroll relative to its parent (LinearLayout) 
            scrollView.requestChildRectangleOnScreen(scrollableContent, viewToScrollRect, false); //ScrollView will make sure, the given viewToScrollRect is visible
        }
    }, delay);
}

1

Androidのソースコードを調べると、既にScrollView–のメンバー関数が存在することがわかりますscrollToChild(View)。これは、要求されたとおりのことを行います。残念ながら、この関数はとマークされprivateた不明瞭な理由で使用されています。その関数に基づいてScrollViewView指定された最初のパラメーターをパラメーターとして見つけ、それをスクロールして内に表示されるようにする次の関数を記述しましたScrollView

 private void make_visible(View view)
 {
  int vt = view.getTop();
  int vb = view.getBottom();

  View v = view;

  for(;;)
     {
      ViewParent vp = v.getParent();

      if(vp == null || !(vp instanceof ViewGroup))
         break;

      ViewGroup parent = (ViewGroup)vp;

      if(parent instanceof ScrollView)
        {
         ScrollView sv = (ScrollView)parent;

         // Code based on ScrollView.computeScrollDeltaToGetChildRectOnScreen(Rect rect) (Android v5.1.1):

         int height = sv.getHeight();
         int screenTop = sv.getScrollY();
         int screenBottom = screenTop + height;

         int fadingEdge = sv.getVerticalFadingEdgeLength();

         // leave room for top fading edge as long as rect isn't at very top
         if(vt > 0)
            screenTop += fadingEdge;

         // leave room for bottom fading edge as long as rect isn't at very bottom
         if(vb < sv.getChildAt(0).getHeight())
            screenBottom -= fadingEdge;

         int scrollYDelta = 0;

         if(vb > screenBottom && vt > screenTop) 
           {
            // need to move down to get it in view: move down just enough so
            // that the entire rectangle is in view (or at least the first
            // screen size chunk).

            if(vb-vt > height) // just enough to get screen size chunk on
               scrollYDelta += (vt - screenTop);
            else              // get entire rect at bottom of screen
               scrollYDelta += (vb - screenBottom);

             // make sure we aren't scrolling beyond the end of our content
            int bottom = sv.getChildAt(0).getBottom();
            int distanceToBottom = bottom - screenBottom;
            scrollYDelta = Math.min(scrollYDelta, distanceToBottom);
           }
         else if(vt < screenTop && vb < screenBottom) 
           {
            // need to move up to get it in view: move up just enough so that
            // entire rectangle is in view (or at least the first screen
            // size chunk of it).

            if(vb-vt > height)    // screen size chunk
               scrollYDelta -= (screenBottom - vb);
            else                  // entire rect at top
               scrollYDelta -= (screenTop - vt);

            // make sure we aren't scrolling any further than the top our content
            scrollYDelta = Math.max(scrollYDelta, -sv.getScrollY());
           }

         sv.smoothScrollBy(0, scrollYDelta);
         break;
        }

      // Transform coordinates to parent:
      int dy = parent.getTop()-parent.getScrollY();
      vt += dy;
      vb += dy;

      v = parent;
     }
 }

1

私の解決策は:

            int[] spinnerLocation = {0,0};
            spinner.getLocationOnScreen(spinnerLocation);

            int[] scrollLocation = {0, 0};
            scrollView.getLocationInWindow(scrollLocation);

            int y = scrollView.getScrollY();

            scrollView.smoothScrollTo(0, y + spinnerLocation[1] - scrollLocation[1]);

1
 scrollView.post(new Runnable() {
                    @Override
                    public void run() {
                        scrollView.smoothScrollTo(0, myTextView.getTop());

                    }
                });

私の実際のプロジェクトからの回答。

ここに画像の説明を入力してください


0

私の場合、それはないEditText、ということgoogleMap。そして、それはこのようにうまく機能します。

    private final void focusCenterOnView(final ScrollView scroll, final View view) {
    new Handler().post(new Runnable() {
        @Override
        public void run() {
            int centreX=(int) (view.getX() + view.getWidth()  / 2);
            int centreY= (int) (view.getY() + view.getHeight() / 2);
            scrollView.smoothScrollBy(centreX, centreY);
        }
    });
}

0

Que:プログラムでスクロールビューを特定のedittextにスクロールする方法はありますか?

Ans:recyclerviewのネストされたスクロールビューの最後の位置にレコードデータが追加されました。

adapter.notifyDataSetChanged();
nested_scroll.setScrollY(more Detail Recycler.getBottom());

プログラムでスクロールビューを特定の編集テキストにスクロールする方法はありますか?


なぜそれは底ですか?
Android開発者

0

以下は私が使用しているものです:

int amountToScroll = viewToShow.getBottom() - scrollView.getHeight() + ((LinearLayout.LayoutParams) viewToShow.getLayoutParams()).bottomMargin;
// Check to see if scrolling is necessary to show the view
if (amountToScroll > 0){
    scrollView.smoothScrollTo(0, amountToScroll);
}

これは、ビューの下部にあるマージンを含む、ビューの下部を表示するために必要なスクロール量を取得します。


0

垂直スクロール、フォームに適しています。回答はアーマダリバロック水平スクロールに基づいています。

private final void focusOnView(final HorizontalScrollView scroll, final View view) {
    new Handler().post(new Runnable() {
        @Override
        public void run() {
            int top = view.getTop();
            int bottom = view.getBottom();
            int sHeight = scroll.getHeight();
            scroll.smoothScrollTo(0, ((top + bottom - sHeight) / 2));
        }
    });
}

HorizontalScrollViewこの方法でを使用する必要がありますか?
Shahood ul Hassan

0

次のObjectAnimatorように使用できます:

ObjectAnimator.ofInt(yourScrollView, "scrollY", yourView.getTop()).setDuration(1500).start();

0

シェリフの答えに基づいて、以下は私のユースケースに最もうまくいきました。注目すべき変更は、のgetTop()代わりgetBottom()とのsmoothScrollTo()代わりですscrollTo()

    private void scrollToView(final View view){
        final ScrollView scrollView = findViewById(R.id.bookmarksScrollView);
        if(scrollView == null) return;

        scrollView.post(new Runnable() {
            @Override
            public void run() {
                scrollView.smoothScrollTo(0, view.getTop());
            }
        });
    }

-1

scrlMainがNestedScrollViewの場合、次を使用します。

scrlMain.post(new Runnable() {
                    @Override
                    public void run() {
                        scrlMain.fullScroll(View.FOCUS_UP);

                    }
                });
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.