프로그래밍 방식으로 스크롤보기를 특정 편집 텍스트로 스크롤하는 방법이 있습니까?


206

스크롤보기로 매우 긴 활동이 있습니다. 사용자가 작성 해야하는 다양한 필드가있는 양식입니다. 양식의 절반 아래에 확인란이 있으며 사용자가 확인하면보기의 특정 부분으로 스크롤하고 싶습니다. 프로그래밍 방식으로 EditText 객체 (또는 다른 뷰 객체)로 스크롤하는 방법이 있습니까?

또한 X 및 Y 좌표를 사용하여 이것이 가능하다는 것을 알고 있지만 양식이 사용자마다 변경 될 수 있으므로이 작업을 피하고 싶습니다.


3
the form may changed from user to user하지만 당신은 그냥 사용할 수 있습니다mEditView.getTop();
— nebkat

1
누군가 CoordinatorLayout 내에서 NestedScrollView를 사용하는 경우 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 ())을 사용하면 더 나은 결과 (원하는보기로 스크롤하는 smother)가 있지만 그 외에는 큰 답변을 얻었습니다.
— Muzikant

18
@ xmenW.K. 짧은 대답 : UI는 할 일을 기반으로 작업을 수행하고 기본적으로 UI 스레드에 알리기 때문에 이전에해야 할 모든 작업을 수행 한 후에는이 작업을 수행 할 수 있습니다 (스크롤) . 기본적으로 스크롤을 대기열에 넣고 요청하기 전에 수행 한 작업의 순서를 고려하여 스레드가 가능한 한 스레드가 수행하도록합니다.
— Martin Marconcini

37
새로운 핸들러를 인스턴스화하는 대신 Runnable을 ScrollView 자체에 게시 할 수도 있습니다.your_scrollview.post(...
— Sherif elKhatib

getBottom () 대신에 중심을 얻는 방법이 있습니까? 내 사건은 EditText 대신 googleMap입니다.
— Zin Win Htet

5
getBottom () 및 getTop ()는 상위에 상대적인
— cambunctious

57

보기를 스크롤보기의 중앙으로 스크롤 하려는 경우 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사용

...
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

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
뷰 페이저 내에서 나를 위해 일한 스크롤보기가 있으며 여기에 언급 된 코드를 사용하여 현재 작동하는 뷰로 스크롤해야합니다.
— Pankaj 2016 년

2
분명히 이것은 대답이 받아 들여 져야합니다. scrollview.smoothScrollTo필요한보기가 화면 밖에서 작동하지 않으면 작동하지 않습니다 (sdk 버전 26의 Android 에뮬레이터에서 시도)
— Sony

@Michael 포장해야합니까 new Handler().post()?
— Johnny Five

@JohnnyFive이 코드를 사용하는 컨텍스트에 따라 다릅니다.
— Michael

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 ()은 뷰에 포함 된 좌표를보고하는 것처럼 보였으므로 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

나는 이것이 더 나은 대답을하기에는 너무 늦을 수도 있지만 원하는 완벽한 솔루션은 포지셔너와 같은 시스템이어야합니다. 내 말은, 시스템이 Editor 필드의 위치를 ​​지정할 때 UI / UX 규칙처럼 완벽하게 키보드까지 필드를 배치합니다.

아래 코드는 안드로이드 방식을 부드럽게 배치하는 것입니다. 우선 현재 스크롤 포인트를 참조 포인트로 유지합니다. 두 번째는 편집기에 가장 적합한 위치 지정 스크롤 포인트를 찾고이를 위해 맨 위로 스크롤 한 다음 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

안드로이드 소스 코드를 살펴보면 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 : 프로그래밍 방식으로 스크롤보기를 특정 편집 텍스트로 스크롤하는 방법이 있습니까?

Ans : recyclerview의 마지막 스크롤보기에 레코드 데이터가 추가되었습니다.

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

세로 스크롤, 양식에 적합합니다. 대답은 Ahmadalibaloch 가로 스크롤을 기반으로합니다.

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

Sherif의 답변을 바탕으로 다음은 내 유스 케이스에 가장 효과적이었습니다. 주목할만한 변경 사항은 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.