Có cách nào để lập trình cuộn chế độ xem cuộn sang văn bản chỉnh sửa cụ thể không?


206

Tôi có một hoạt động rất dài với một scrollview. Đó là một biểu mẫu với nhiều trường khác nhau mà người dùng phải điền vào. Tôi có một hộp kiểm nằm xuống một nửa biểu mẫu của tôi và khi người dùng kiểm tra nó, tôi muốn cuộn đến một phần cụ thể của chế độ xem. Có cách nào để cuộn đến một đối tượng EditText (hoặc bất kỳ đối tượng xem nào khác) theo lập trình không?

Ngoài ra, tôi biết điều này là có thể khi sử dụng các hợp âm X và Y nhưng tôi muốn tránh làm điều này vì hình thức có thể thay đổi từ người dùng sang người dùng.


3
the form may changed from user to usernhưng bạn chỉ có thể sử dụngmEditView.getTop();
nebkat

1
nếu ai đó đang sử dụng NestedScrollView trong Điều phối viên, bạn có thể cuộn đến một chế độ xem cụ thể qua stackoverflow.com/questions/52083678/
Kẻ

Câu trả lời:


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

129
Tôi thấy rằng sử dụng smoothScrollTo (0, your_EditBox.getTop ()) sẽ có kết quả tốt hơn (cuộn mượt hơn đến chế độ xem mong muốn) nhưng khác với điều đó - câu trả lời tuyệt vời.
Muzikant

18
@ xmenW.K. Trả lời ngắn: bởi vì UI thực hiện công việc của nó dựa trên hàng đợi những việc cần làm và về cơ bản bạn đang nói về luồng UI, khi bạn có thể, sau khi bạn đã làm tất cả những gì bạn phải làm trước đây, hãy làm điều này (cuộn) . Về cơ bản, bạn đang cuộn cuộn trong hàng đợi và để cho luồng thực hiện khi có thể, tôn trọng thứ tự của những việc nó đang làm trước khi bạn yêu cầu.
Martin Marconcini

37
Cũng có thể đăng Runnable lên ScrollView thay vì khởi tạo Handler mới:your_scrollview.post(...
Sherif elKhatib

Có phương pháp nào để lấy trung tâm chế độ xem thay vì getBottom () không? Vì trường hợp của tôi là googleMap thay vì EditText.
Zin Win Htet 15/03/2016

5
getBottom () và getTop () có liên quan đến cha mẹ
lịch sử vào

55

Câu trả lời của Sherif elKhatib có thể được cải thiện rất nhiều, nếu bạn muốn cuộn chế độ xem đến trung tâm của chế độ xem cuộn . Phương pháp có thể sử dụng lại này giúp cuộn trơn tru khung nhìn đến trung tâm có thể nhìn thấy của ngang dọc.

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

Đối với một ScrollViewsự thay đổi theo chiều dọc xyvị trí của đầu vào smoothScroll. Và sử dụng view.getTop()thay vì view.getLeft()view.getBottom()thay vì v.getRight().

:)


3
Bạn phải điều chỉnh mã của bạn. Bạn phải lấy chiều rộng của chế độ xem cuộn và bạn phải thay đổi công thức thành sv.smoothScrollTo (((vLeft + vRight) / 2) - (svWidth / 2), 0);
Tiểu học

2
Nếu không, chế độ xem trong cuộn sẽ không được căn giữa. Tôi đã thực hiện chỉnh sửa cho bạn.
Tiểu học

Bạn đã kiểm tra công thức hoạt động chính xác chưa, bởi vì công thức cũ hoạt động tốt với tôi
ahmadalibaloch

1
@Euityary Công thức của bạn và ahmads là các phiên bản đơn giản và mở rộng của cùng một biểu thức đại số, không cần điều chỉnh.
k29

1
@ k29 bạn có đề cập đến hai công thức có thể nhìn thấy ở đây không? Cả hai đều từ tôi, tôi tiếp tục đơn giản hóa công thức nhận xét của mình và chỉnh sửa câu trả lời cho phù hợp. Nhưng tất cả phần còn lại vẫn giống với câu trả lời ban đầu và cũng rất hữu ích cho tôi.
Tiểu học

51

Công việc này tốt cho tôi :

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

công khai void RequestChildF Focus (Xem con, Xem tập trung)

đứa trẻ - Đứa trẻ của ViewParent này muốn tập trung. Chế độ xem này sẽ chứa chế độ xem tập trung. Nó không nhất thiết là quan điểm thực sự có trọng tâm.

tập trung - Quan điểm là hậu duệ của trẻ em thực sự có trọng tâm


Xem loại nhảy trong bất kỳ cuộn trơn tru nào
silentsudo

32

Theo tôi cách tốt nhất để cuộn đến một hình chữ nhật đã cho là thông qua View.requestRectangleOnScreen(Rect, Boolean). Bạn nên gọi nó trên một Viewbạn muốn cuộn đến và vượt qua một hình chữ nhật cục bộ mà bạn muốn hiển thị trên màn hình. Tham số thứ hai nên falseđể cuộn trơn tru và trueđể cuộn ngay lập tức.

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

1
Làm việc cho tôi bên trong một máy nhắn tin chế độ xem có scrollview và cần cuộn đến một chế độ xem hiện đang hoạt động bằng cách sử dụng mã được đề cập ở đây.
Pankaj

2
Chắc chắn câu trả lời này phải là câu trả lời được chấp nhận, scrollview.smoothScrollTosẽ không hoạt động nếu chế độ xem được yêu cầu tắt màn hình, (đã thử trong trình giả lập Android với phiên bản sdk 26)
Sony

@Michael Có nên quấn new Handler().post()?
Johnny Five

@JohnnyFive Nó phụ thuộc vào ngữ cảnh nơi bạn sử dụng mã này.
Michael

12

Tôi đã thực hiện một phương thức tiện ích nhỏ dựa trên Trả lời từ WarrenFaith, mã này cũng sẽ được tính đến nếu chế độ xem đó đã hiển thị trong cuộn xem, không cần cuộn.

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

Tôi đoán scrollBoundsnên là tham số cho scrollView.getHitRectphương thức.
Vijay C

10

Bạn nên TextViewtập trung vào yêu cầu của bạn :

    mTextView.requestFocus();

7

EditText của tôi được lồng một số lớp trong ScrollView của tôi, bản thân nó không phải là chế độ xem gốc của bố cục. Vì getTop () và getBottom () dường như báo cáo tọa độ trong chế độ xem chứa nó, nên tôi đã tính toán khoảng cách từ đỉnh ScrollView đến đỉnh EditText bằng cách lặp qua cha mẹ của 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

Một phương sai khác sẽ là:

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

hoặc bạn có thể sử dụng post()phương pháp.


5

Tôi biết điều này có thể là quá muộn để có câu trả lời tốt hơn nhưng một giải pháp hoàn hảo mong muốn phải là một hệ thống như định vị. Ý tôi là, khi hệ thống tạo định vị cho trường Editor, nó đặt trường chỉ lên bàn phím, do đó, quy tắc UI / UX là hoàn hảo.

Những gì bên dưới mã làm cho là cách định vị Android trơn tru. Trước hết chúng tôi giữ điểm cuộn hiện tại làm điểm tham chiếu. Điều thứ hai là tìm điểm cuộn định vị tốt nhất cho trình soạn thảo, để thực hiện điều này, chúng tôi cuộn lên trên cùng, sau đó yêu cầu các trường soạn thảo tạo thành phần ScrollView để thực hiện định vị tốt nhất. Gatcha! Chúng tôi đã học được vị trí tốt nhất. Bây giờ, những gì chúng ta sẽ làm là cuộn trơn tru từ điểm trước đến điểm chúng ta mới tìm thấy. Nếu bạn muốn, bạn có thể bỏ qua việc cuộn trơn tru bằng cách sử dụng scrollTo thay vì smoothScrollTo .

LƯU Ý: ScrollView container chính là trường thành viên có tên scrollViewSignup, vì ví dụ của tôi là màn hình đăng ký, vì bạn có thể tìm ra rất nhiều.

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

Nếu bạn muốn sử dụng khối này cho tất cả các phiên bản EditText và nhanh chóng tích hợp nó với mã màn hình của bạn. Bạn chỉ có thể thực hiện một traverser như dưới đây. Để làm điều này, tôi đã biến OnF FocusChangeListener chính thành một trường thành viên có tên là FocusChangeListenerToScrollEditor và gọi nó trong onCreate như dưới đây.

traverseEditTextChildren(scrollViewSignup, focusChangeListenerToScrollEditor);

Và phương pháp thực hiện như dưới đây.

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

Vì vậy, những gì chúng tôi đã làm ở đây là làm cho tất cả trẻ em EditText gọi người nghe tập trung.

Để đạt được giải pháp này, tôi đã kiểm tra tất cả các giải pháp tại đây và tạo ra một giải pháp mới cho kết quả UI / UX tốt hơn.

Rất cám ơn tất cả các câu trả lời khác truyền cảm hứng cho tôi nhiều.

3

Các câu trả lời trên sẽ hoạt động tốt nếu ScrollView là cha mẹ trực tiếp của ChildView. Nếu ChildView của bạn đang được bọc trong một Viewgroup khác trong ScrollView, nó sẽ gây ra hành vi không mong muốn vì View.getTop () có được vị trí liên quan đến cha mẹ của nó. Trong trường hợp như vậy, bạn cần thực hiện điều này:

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

Đây là giải pháp toàn diện nhất vì nó cũng chiếm các vị trí phụ huynh. Cảm ơn vì đăng!
Gustavo Baiocchi Costa


2

Tôi nghĩ rằng tôi đã tìm thấy giải pháp dễ thanh lịch hơn và ít lỗi hơn bằng cách sử dụng

ScrollView.requestChildRonymousOnScreen

Không có toán học liên quan, và trái với các giải pháp được đề xuất khác, nó sẽ xử lý cuộn chính xác cả lên và xuống.

/**
 * 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
}

Đó là một ý tưởng tốt để bọc nó postDelayedđể làm cho nó đáng tin cậy hơn, trong trường hợp ScrollViewnó đang được thay đổi vào lúc này

/**
 * 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

Kiểm tra mã nguồn Android, bạn có thể thấy rằng đã có chức năng thành viên của ScrollView- scrollToChild(View)- đó chính xác là những gì được yêu cầu. Thật không may, chức năng này là vì một số lý do mơ hồ được đánh dấu private. Dựa trên hàm đó, tôi đã viết hàm sau tìm hàm đầu tiên ScrollViewbên trên Viewđược chỉ định làm tham số và cuộn nó để nó hiển thị trong 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

Giải pháp của tôi là:

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

                    }
                });

Trả lời từ dự án thực tế của tôi.

nhập mô tả hình ảnh ở đây


0

Trong trường hợp của tôi, đó không phải EditText, đó là googleMap. Và nó hoạt động thành công như thế này.

    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: Có cách nào để lập trình cuộn chế độ xem cuộn sang một edittext cụ thể không?

Trả lời: Chế độ xem cuộn lồng nhau trong recyclerview vị trí cuối cùng đã thêm dữ liệu bản ghi.

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

Có cách nào để lập trình cuộn chế độ xem cuộn sang văn bản chỉnh sửa cụ thể không?


Tại sao nó là đáy?
nhà phát triển Android

0

Sau đây là những gì tôi đang sử dụng:

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

Điều này nhận được số lượng cuộn cần thiết để hiển thị dưới cùng của chế độ xem, bao gồm bất kỳ lề nào ở dưới cùng của chế độ xem đó.


0

Cuộn dọc, tốt cho các hình thức. Câu trả lời được dựa trên cuộn ngang của 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));
        }
    });
}

bạn có chắc là bạn nên sử dụng HorizontalScrollViewphương pháp này không?
Shahood ul Hassan

0

Bạn có thể sử dụng ObjectAnimatornhư thế này:

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

0

Dựa trên câu trả lời của Sherif, những điều sau đây hoạt động tốt nhất cho trường hợp sử dụng của tôi. Thay đổi đáng chú ý là getTop()thay vì getBottom()smoothScrollTo()thay vì 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

Nếu scrlMain là NestedScrollView của bạn, thì hãy sử dụng như sau,

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

                    }
                });
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.