Чи існує спосіб програмного прокручування подання прокрутки до певного тексту редагування?


206

У мене дуже тривала активність із прокруткою. Користувач повинен заповнити форму з різними полями. У мене є прапорець на півдорозі моєї форми, і коли користувач перевіряє її, я хочу перейти до певної частини представлення. Чи є можливість програмно прокрутити до об'єкта EditText (або будь-якого іншого об’єкта перегляду)?

Крім того, я знаю, що це можливо за допомогою X і Y-координат, але я хочу уникати цього, оскільки форма може змінюватися від користувача до користувача.


3
the form may changed from user to userале ви можете просто скористатисяmEditView.getTop();
nebkat

1
якщо хто - то використовує NestedScrollView в CoordinatorLayout, ви можете прокручувати вид конкретного через stackoverflow.com/questions/52083678 / ...
user1506104

Відповіді:


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 ()) дає кращий результат (більш плавне прокручування до потрібного вигляду), але крім цього - чудова відповідь.
Muzikant

18
@ xmenW.K. Короткий відповідь: оскільки користувальницький інтерфейс виконує свою роботу на основі черги, що потрібно зробити, і ви в основному говорите потік користувальницького інтерфейсу, коли ви можете, після того, як ви зробили все, що мали зробити раніше, зробіть це (прокрутіть) . Ви в основному ставите прокрутку в чергу і дозволяєте потоці робити це, коли можна, дотримуючись порядку речей, які вони робили, перш ніж ви запитували.
Мартін Марконніні

37
Також можна опублікувати Runnable на ScrollView замість того, щоб створити новий обробник:your_scrollview.post(...
Sherif elKhatib

Чи існує якийсь метод отримання центру зору, а не getBottom ()? Тому що мій випадок - googleMap замість EditText.
Zin Win Htet

5
getBottom () та getTop () відносяться до батьків
камбунктуальний

57

Відповідь Шерифа ельКатіба може бути значно покращена, якщо ви хочете прокрутити погляд до центру подання прокрутки . Цей метод багаторазового використання плавно прокручує погляд до видимого центру HorizontalScrollView.

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 Ваші формули та ахмади - це спрощені та розширені версії того ж алгебраїчного виразу, що коректувати не потрібно.
k29

1
@ k29 ви посилаєтесь на дві видимі формули тут? Вони обоє від мене, я ще більше спростив формулу свого коментаря і відповідно відредагував відповідь. Але все інше все одно те саме з оригінальної відповіді і мені також було дуже корисно.
Елементарно

51

Це добре для мене:

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

public void RequestChildFocus (Перегляд дитини, зосереджено погляд)

дитина - дитина цього ViewParent, яка хоче зосередити увагу. Цей вид буде містити зосереджений вид. Не обов'язково погляд, який насправді має фокус.

сфокусований - погляд, який є нащадком дитини, який насправді має фокус


Перегляд різновидів стрибків у будь-якому плавному прокрутку
silentsudo

32

На мою думку, найкращий спосіб прокрутити до заданого прямокутника - це через View.requestRectangleOnScreen(Rect, Boolean). Вам слід зателефонувати на те, до якого Viewви хочете прокрутити та передати локальний прямокутник, який ви хочете бачити на екрані. Другий параметр повинен бути falseдля плавного прокручування та trueдля негайного прокручування.

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

1
Для мене працював всередині пейджер перегляду, є перегляд прокрутки і потрібно прокрутити до представлення, яке працює зараз, використовуючи вказаний тут код.
Панкай

2
Однозначно, це має бути прийнятою відповіддю, scrollview.smoothScrollToне спрацює, якщо потрібний перегляд вимкнеться з екрана, (спробували андроїд-емулятор з sdk версія 26)
Sony

@Michael Я повинен завернути new Handler().post()?
Джонні П'ять

@JohnnyFive Це залежить від контексту, де ви використовуєте цей код.
Майкл

12

Я зробив невеликий корисний метод на основі відповіді від WarrenFaith, цей код також враховує, якщо цей вид уже видно в перегляді прокрутки, немає необхідності в прокрутці.

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 () повідомляють про координати всередині його перегляду, я мав обчислити відстань від вершини ScrollView до вершини EditText шляхом ітерації через батьків 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. Перш за все, ми зберігаємо поточну точку прокрутки як опорну точку. Друга річ - знайти найкращу точку прокрутки позиціонування для редактора, для цього ми прокручуємо верх, а потім запитуємо поля редактора, щоб компонент ScrollView зробив найкраще позиціонування. Гатча! Ми дізналися найкращу позицію. Тепер ми будемо плавно прокручувати з попередньої точки до точки, яку ми знайшли нещодавно. Якщо ви хочете, ви можете пропустити плавне прокручування, використовуючи scrollTo, а не smoothScrollTo .

ПРИМІТКА . Основний контейнер 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 завернуто в інший ViewGroup у ScrollView, це спричинить несподівану поведінку, оскільки 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));
}

Це найбільш комплексне рішення, оскільки воно враховує і позиції батьків. Дякуємо за публікацію!
Густаво Байоккі Коста


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. На основі цієї функції я написав наступну функцію, яка знаходить першу ScrollViewвище Viewвказану як параметр і прокручує її, щоб вона стала видимою в межах 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: Чи існує спосіб програмного прокручування подання прокрутки до певного редакційного тексту?

Відповідь: Вкладений вид прокрутки в останній позиції reciler додав дані запису.

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

Чи існує спосіб програмного прокручування подання прокрутки до певного тексту редагування?


Чому саме дно?
андроїд розробник

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цей метод?
Шейцій уль Хасан

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);

                    }
                });
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.