Android: ScrollView buộc xuống dưới


200

Tôi muốn một ScrollView để bắt đầu tất cả các cách ở phía dưới. Phương pháp nào?


1
Tôi nghĩ rằng nó chỉ là scrollTo (), phải, tôi vừa kiểm tra các tài liệu dev cho ScrollView. Dễ như ăn bánh.

Câu trả lời:


274

scroll.fullScroll(View.FOCUS_DOWN) cũng nên làm việc.

Đặt cái này vào scroll.Post(Runnable run)

Mã Kotlin

scrollView.post {
   scrollView.fullScroll(View.FOCUS_DOWN)
}

6
Điều đó dường như không làm bất cứ điều gì, bất kỳ đề nghị? Tôi đã thử nó trên onCreate và sau đó là nút onClick.
RichardJohnn

Nó dường như không làm việc để thay đổi định hướng. Nếu không thì nó hoạt động.
Prashant

1
Điều này không hoạt động nếu kích thước bố trí đã thay đổi ngay trước khi gọi nó. Nó cần phải được đăng thay thế.
MLProgrammer-CiM

2
Điều này và bên dưới, sẽ không hoạt động cho đến khi bạn dành một chút thời gian để xem hoàn toàn, chỉ đơn giản hóa câu trả lời ademar. scrollView.postDelayed (new Runnable () {@Override public void run () {scrollView.fullScroll (View.FOCUS_UP // Hoặc Xuống);}}, 1000);
EngineSense

scroll.fullScroll (View.FOCUS_DOWN) sẽ dẫn đến thay đổi tiêu điểm. Điều đó sẽ mang lại một số hành vi kỳ lạ khi có nhiều hơn một chế độ xem có thể tập trung, ví dụ: hai EditText. Kiểm tra một giải pháp khác tôi cung cấp ở phía dưới.
hòa bình

332

bạn nên chạy mã bên trong scroll.post như thế này:

scroll.post(new Runnable() {            
    @Override
    public void run() {
           scroll.fullScroll(View.FOCUS_DOWN);              
    }
});

4
Có một số cách mà không mất phần tử hiện tại tập trung, khi tôi làm điều này, tôi mất trọng tâm của phần tử hiện tại của mình (khác với scrollview)
rkmax

2
Điều này chỉ cần thiết trong trường hợp bố cục chưa được đo và bố trí (ví dụ: nếu bạn chạy nó trong onCreate). Trong các trường hợp như nhấn nút, .post () là không cần thiết.
Patrick Boos

12
Nếu bạn không muốn tập trung vào ScrollView, bạn có thể sử dụng scroll.scrollTo(0, scroll.getHeight());để nhảy xuống dưới hoặc scroll.smoothScrollTo(0, scroll.getHeight());để cuộn mượt hơn
yuval

Không phải mã này có thể bị rò rỉ bộ nhớ? Một Runnable ẩn danh được tạo để giữ tham chiếu đến chế độ xem hoạt động (cuộn). Nếu hoạt động bị hủy trong khi runnable đang thực thi nhiệm vụ của nó, nó sẽ rò rỉ một tham chiếu đến scrollview, phải không?
Jenever

Tại Kotlin:scrollView.post { scrollView.fullScroll(View.FOCUS_DOWN) }
Albert Vila Calvo

94

scroll.fullScroll(View.FOCUS_DOWN)sẽ dẫn đến sự thay đổi của trọng tâm. Điều đó sẽ mang lại một số hành vi kỳ lạ khi có nhiều hơn một chế độ xem có thể tập trung, ví dụ: hai EditText. Có một cách khác cho câu hỏi này.

    View lastChild = scrollLayout.getChildAt(scrollLayout.getChildCount() - 1);
    int bottom = lastChild.getBottom() + scrollLayout.getPaddingBottom();
    int sy = scrollLayout.getScrollY();
    int sh = scrollLayout.getHeight();
    int delta = bottom - (sy + sh);

    scrollLayout.smoothScrollBy(0, delta);

Điều này hoạt động tốt.

Gia hạn Kotlin

fun ScrollView.scrollToBottom() {
    val lastChild = getChildAt(childCount - 1)
    val bottom = lastChild.bottom + paddingBottom
    val delta = bottom - (scrollY+ height)        
    smoothScrollBy(0, delta)
}

Rất vui vì tôi đã không phải lãng phí thêm thời gian cho việc này. Chỉ cần những gì tôi cần
Alexandre G

6
Điều này nên có nhiều upvote. Đó là câu trả lời tốt nhất cho đến nay.
Eric Lange

1
Đây là câu trả lời tốt nhất hiện tại ở đây.
con trỏ trống

1
Đã thử mọi thứ khác trên trang này, ngay cả cách thức bên dưới này. Đây là điều duy nhất hoạt động và nó không khiến EditText của tôi mất tập trung. Cảm ơn bạn.
Joel

Nếu bạn cần cuộn xuống trong khi bàn phím hiển thị, hãy kết hợp mã này với thư viện này . Hoạt động như một lá bùa.
wonsuc

47

Đôi khi scrollView.post không hoạt động

 scrollView.post(new Runnable() {
        @Override
        public void run() {
            scrollView.fullScroll(ScrollView.FOCUS_DOWN);
        }
    });

NHƯNG nếu bạn sử dụng scrollView.postDelayed, nó chắc chắn sẽ hoạt động

 scrollView.postDelayed(new Runnable() {
        @Override
        public void run() {
            scrollView.fullScroll(ScrollView.FOCUS_DOWN);
        }
    },1000);

cảm ơn đã xác định postDelayed là giải pháp tốt hơn.
Prashant

@Prashant :) :) :)
Ajay Shrestha

1
Chỉ cần nhớ rằng bạn cần loại bỏ Runnable của mình khi bạn kết thúc hoạt động
FabioR

38

Điều làm việc tốt nhất cho tôi là

scroll_view.post(new Runnable() {
     @Override
     public void run() {
         // This method works but animates the scrolling 
         // which looks weird on first load
         // scroll_view.fullScroll(View.FOCUS_DOWN);

         // This method works even better because there are no animations.
         scroll_view.scrollTo(0, scroll_view.getBottom());
     }
});

Tôi đã thử điều này, nhưng thuật toán ở đây là sai. Kiểm tra câu trả lời của tôi ở phía dưới xin vui lòng.
hòa bình

28

Tôi gia tăng để làm việc hoàn hảo.

    private void sendScroll(){
        final Handler handler = new Handler();
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {Thread.sleep(100);} catch (InterruptedException e) {}
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        scrollView.fullScroll(View.FOCUS_DOWN);
                    }
                });
            }
        }).start();
    }

Ghi chú

Câu trả lời này là một cách giải quyết cho các phiên bản Android thực sự cũ. Ngày nay postDelayedkhông còn lỗi đó nữa và bạn nên sử dụng nó.


3
Không phải trên hai, nhưng điều này hoạt động tốt trong điện thoại của tôi (LG JellyBean 4.1.2 Optimus G).
Youngjae

9
Tại sao không sử dụng scrollView.postDelayed (runnable, 100)?
Matt Wolfe

1
@MattWolfe tại thời điểm đó không hoạt động trong một số phiên bản cũ của Android. Nhưng hôm nay câu trả lời này không được chấp nhận.
ademar111190

4
Vì tình yêu của chúa, hãy sử dụng scrollView.postDelayed (runnable, 100)! :)
Alex Lockwood

1
Tôi đã thêm một ghi chú @AlexLockwood Tôi hy vọng mọi người sử dụng postDelayed:)
ademar111190

4

tôi đã thử thành công

scrollView.postDelayed(new Runnable() {
    @Override
    public void run() {
        scrollView.smoothScrollTo(0, scrollView.getHeight());
    }
}, 1000);

3

Khi chế độ xem chưa được tải, bạn không thể cuộn. Bạn có thể thực hiện 'sau' với một bài đăng hoặc cuộc gọi ngủ như trên, nhưng điều này không phải là rất thanh lịch.

Tốt hơn là lập kế hoạch cuộn và thực hiện nó trên onLayout () tiếp theo. Mã ví dụ ở đây:

https://stackoverflow.com/a/10209457/1310343


3

Một điều cần xem xét là những gì KHÔNG được thiết lập. Hãy chắc chắn rằng các điều khiển con của bạn, đặc biệt là các điều khiển EditText, không có bộ thuộc tính RequestF Focus. Đây có thể là một trong những thuộc tính được giải thích cuối cùng trên bố cục và nó sẽ ghi đè cài đặt trọng lực trên bố mẹ của nó (bố cục hoặc ScrollView).


3

Đây là một số cách khác để cuộn xuống dưới cùng

fun ScrollView.scrollToBottom() {
    // use this for scroll immediately
    scrollTo(0, this.getChildAt(0).height) 

    // or this for smooth scroll
    //smoothScrollBy(0, this.getChildAt(0).height)

    // or this for **very** smooth scroll
    //ObjectAnimator.ofInt(this, "scrollY", this.getChildAt(0).height).setDuration(2000).start()
}

Sử dụng

Nếu bạn đã xem xong

my_scroll_view.scrollToBottom()

Nếu cuộn xem của bạn chưa hoàn thành được đặt ra (ví dụ: bạn cuộn xuống dưới cùng trong onCreatephương thức Hoạt động ...)

my_scroll_view.post { 
   my_scroll_view.scrollToBottom()          
}

1

Không chính xác câu trả lời cho câu hỏi, nhưng tôi cần phải cuộn xuống ngay khi một EditText có trọng tâm. Tuy nhiên, câu trả lời được chấp nhận sẽ khiến ET cũng mất tập trung ngay lập tức (với ScrollView tôi giả định).

Cách giải quyết của tôi là như sau:

emailEt.setOnFocusChangeListener(new View.OnFocusChangeListener() {
    @Override
    public void onFocusChange(View v, boolean hasFocus) {
        if(hasFocus){
            Toast.makeText(getActivity(), "got the focus", Toast.LENGTH_LONG).show();
            scrollView.postDelayed(new Runnable() {
                @Override
                public void run() {
                    scrollView.fullScroll(ScrollView.FOCUS_DOWN);
                }
            }, 200);
        }else {
            Toast.makeText(getActivity(), "lost the focus", Toast.LENGTH_LONG).show();
        }
    }
});

1

Tôi thực sự thấy rằng việc gọi fullScroll hai lần thực hiện thủ thuật:

myScrollView.fullScroll(View.FOCUS_DOWN);

myScrollView.post(new Runnable() {
    @Override
    public void run() {
        myScrollView.fullScroll(View.FOCUS_DOWN);
    }
});

Nó có thể có liên quan đến việc kích hoạt phương thức post () ngay sau khi thực hiện cuộn đầu tiên (không thành công). Tôi nghĩ rằng hành vi này xảy ra sau bất kỳ cuộc gọi phương thức nào trước đây trên myScrollView, vì vậy bạn có thể thử thay thế phương thức fullScroll () đầu tiên bằng bất kỳ điều gì khác có thể liên quan đến bạn.


0

Sử dụng có một cách tuyệt vời khác để làm điều này với các coroutines của Kotlin. Ưu điểm của việc sử dụng coroutine trái ngược với Handler với runnable (post / postDelayed) là nó không kích hoạt một luồng đắt tiền để thực hiện một hành động bị trì hoãn.

launch(UI){
    delay(300)
    scrollView.fullScroll(View.FOCUS_DOWN)
}

Điều quan trọng là chỉ định HandlerContext của coroutine là UI nếu không hành động bị trì hoãn có thể không được gọi từ luồng UI.


0

Trong những trường hợp đó chỉ sử dụng scroll.scrollTo (0, sc.getBottom ()) không hoạt động, hãy sử dụng nó bằng scroll.post

Thí dụ:

scroll.post(new Runnable() {
  @Override
  public void run() {
  scroll.fullScroll(View.FOCUS_DOWN);
  } 
});

0

Một lý do scroll.fullScroll(View.FOCUS_DOWN)có thể giải thích tại sao có thể không hoạt động ngay cả khi được bao bọc .post()là chế độ xem không được đặt ra. Trong trường hợp này, View.doOnLayout () có thể là một lựa chọn tốt hơn:

scroll.doOnLayout(){
    scroll.fullScroll(View.FOCUS_DOWN)
}

Hoặc, một cái gì đó chi tiết hơn cho những linh hồn dũng cảm: https://chris.banes.dev/2019/12/03/suspending-view/

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.