Есть ли способ программно прокрутить представление прокрутки к определенному тексту редактирования?

У меня очень длинная деятельность с scrollview. Это форма с различными полями, которые пользователь должен заполнить. У меня есть флажок на полпути вниз по моей форме, и когда пользователь проверяет его, я хочу перейти к определенной части представления. Есть ли способ прокрутить объект EditText (или любой другой объект представления) программно?

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

Ответ 1

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

Ответ 2

Ответ Sherif elKhatib может быть значительно улучшен, если вы хотите прокрутить представление до центра прокрутки.. Этот многоразовый метод плавно прокручивает представление к видимому центру 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 измените положение x и y входов smoothScroll. И используйте view.getTop() вместо view.getLeft() и view.getBottom() вместо v.getRight().

:)

Ответ 3

Это хорошо работает для меня:

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

public void RequestChildFocus (просмотр дочернего объекта, просмотр сфокусирован)

дочерний - ребенок этого ViewParent, который хочет сосредоточиться. Это представление будет содержать сфокусированное представление. Это не обязательно то, что на самом деле имеет фокус.

сфокусировано - представление, которое является потомком ребенка, на самом деле имеющим фокус

Ответ 4

По-моему, лучший способ прокрутки до заданного прямоугольника - View.requestRectangleOnScreen(Rect, Boolean). Вы должны вызвать его на View, который вы хотите прокрутить, и передать локальный прямоугольник, который вы хотите видеть на экране. Второй параметр должен быть false для плавной прокрутки и true для непосредственной прокрутки.

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

Ответ 5

Я сделал небольшой метод утилиты, основанный на ответе от 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());
            }
        });
    } 
}

Ответ 6

Вы должны сделать фокус запроса TextView:

    mTextView.requestFocus();

Ответ 7

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

Ответ 8

Еще одно изменение:

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

или вы можете использовать метод post().

Ответ 9

Я знаю, что может быть слишком поздно для лучшего ответа, но желаемым идеальным решением должна быть система, подобная позиционеру. Я имею в виду, что когда система позиционирует поле редактора, она размещает поле только на клавиатуре, так что, согласно правилам 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 и быстро интегрировать его с вашим кодом экрана. Вы можете просто сделать traverser как ниже. Для этого я сделал основной 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.

Many thanks to all other answers inspiring me much.

Ответ 10

ссылка: fooobar.com/questions/47272/...

Следование работало намного лучше.

mObservableScrollView.post(new Runnable() {
            public void run() { 
                mObservableScrollView.fullScroll([View_FOCUS][1]); 
            }
        });

Ответ 11

Я думаю, что нашел более элегантное и менее подверженное ошибкам решение с использованием

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

Ответ 12

Вышеуказанные ответы будут работать нормально, если 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));
}

Ответ 13

Мое решение:

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

Ответ 14

Изучая исходный код 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;
     }
 }

Ответ 15

В моем случае это не 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);
        }
    });
}

Ответ 16

Que: есть ли способ программно прокрутить представление прокрутки к определенному редактору?

Ans: просмотр вложенной прокрутки в последней записи добавленной записи recyclerview добавлен.

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

Есть ли способ программно прокрутить представление прокрутки к определенному тексту редактирования?

Ответ 17

Ниже я использую следующее:

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

Это получает количество прокрутки, необходимое для отображения нижней части представления, включая любое поле в нижней части этого представления.

Ответ 18

Вертикальный свиток, хорош для форм. Ответ основан на горизонтальном свитке Ахмадалибалоха.

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

Ответ 19

Вы можете использовать ObjectAnimator следующим образом:

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

Ответ 20

Если scrlMain является вашим NestedScrollView, используйте следующие,

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

                    }
                });