Android: ScrollView บังคับให้ด้านล่าง


200

ฉันต้องการให้ ScrollView เริ่มต้นจนสุดทาง วิธีใด?


1
ฉันคิดว่ามันแค่ scrollTo () ใช่ฉันเพิ่งตรวจสอบ dev เอกสารสำหรับ ScrollView peasy ง่าย ๆ
Noah Seidman

คำตอบ:


274

scroll.fullScroll(View.FOCUS_DOWN) ควรทำงานเช่นกัน

ใส่สิ่งนี้ใน scroll.Post(Runnable run)

รหัส Kotlin

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

6
ดูเหมือนจะไม่ทำอะไรเลยคำแนะนำใด ๆ ฉันลองใช้ onCreate และใหม่กว่าใน onClick เพียงปุ่มเดียว
RichardJohnn

ดูเหมือนจะไม่ทำงานกับการเปลี่ยนทิศทาง มิฉะนั้นมันทำงาน
Prashant

1
วิธีนี้ใช้ไม่ได้หากขนาดเค้าโครงเปลี่ยนไปก่อนเรียก จำเป็นต้องโพสต์แทน
MLProgrammer-CiM

2
สิ่งนี้และด้านล่างจะไม่ทำงานจนกว่าคุณจะให้เวลากับมุมมองที่จะขยายอย่างเต็มที่เพียงทำให้คำตอบ ademar ง่ายขึ้น scrollView.postDelayed (Runnable ใหม่ () {@Override โมฆะสาธารณะวิ่ง () {scrollView.fullScroll (View.FOCUS_UP // หรือลง);}}, 1,000);
EngineSense

scroll.fullScroll (ดู FOCUS_DOWN) จะนำไปสู่การเปลี่ยนโฟกัส สิ่งนี้จะทำให้เกิดพฤติกรรมแปลก ๆ เมื่อมีมุมมองที่สามารถโฟกัสได้มากกว่าหนึ่งมุมมองเช่น EditText สองรายการ ตรวจสอบวิธีแก้ไขปัญหาอื่นที่ฉันมีให้ที่ด้านล่าง
สงบสุข

332

คุณควรเรียกใช้รหัสภายใน scroll.post ดังนี้:

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

4
มีวิธีการบางอย่างโดยไม่ต้องสูญเสียองค์ประกอบโฟกัสปัจจุบันเมื่อฉันทำเช่นนี้ฉันสูญเสียความสำคัญขององค์ประกอบปัจจุบันของฉัน (แตกต่างจาก scrollview)
rkmax

2
จำเป็นต้องใช้ในกรณีที่ยังไม่ได้วัดและจัดวางเลย์เอาต์ (เช่นถ้าคุณเรียกใช้ใน onCreate) ในกรณีเช่นกดปุ่มไม่จำเป็นต้องใช้. post ()
Patrick Boos

12
หากคุณไม่ต้องการมุ่งเน้นไปที่ ScrollView คุณสามารถใช้scroll.scrollTo(0, scroll.getHeight());เพื่อข้ามไปยังด้านล่างหรือscroll.smoothScrollTo(0, scroll.getHeight());เพื่อการเลื่อนที่นุ่มนวลขึ้น
yuval

รหัสนี้อาจเป็นหน่วยความจำรั่วหรือไม่ Runnable ที่ไม่ระบุชื่อถูกสร้างขึ้นซึ่งเก็บการอ้างอิงไปยังมุมมองกิจกรรม (เลื่อน) หากกิจกรรมถูกทำลายในขณะที่ runnable กำลังทำงานของมันกิจกรรมนั้นจะรั่วไหลไปอ้างอิงกับ scrollview ใช่ไหม?
Jenever

ใน Kotlin:scrollView.post { scrollView.fullScroll(View.FOCUS_DOWN) }
Albert Vila Calvo

94

scroll.fullScroll(View.FOCUS_DOWN)จะนำไปสู่การเปลี่ยนโฟกัส สิ่งนี้จะทำให้เกิดพฤติกรรมแปลก ๆ เมื่อมีมุมมองที่สามารถโฟกัสได้มากกว่าหนึ่งมุมมองเช่น EditText สองรายการ มีวิธีอื่นสำหรับคำถามนี้

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

มันใช้งานได้ดี

Kotlin Extension

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

ดีใจที่ฉันไม่ต้องเสียเวลากับเรื่องนี้อีก สิ่งที่ฉันต้องการ
Alexandre G

6
ควรมี upvotes มากกว่านี้ มันเป็นคำตอบที่ดีที่สุด
Eric Lange

1
นี่คือคำตอบที่ดีที่สุดในปัจจุบันที่นี่
ตัวชี้โมฆะ

1
พยายามทุกอย่างในหน้านี้แม้แต่สิ่งที่อยู่ด้านล่างนี้ นี่เป็นสิ่งเดียวที่ทำงานได้และไม่ทำให้ EditText ของฉันเสียสมาธิ ขอบคุณ.
Joel

หากคุณต้องการเลื่อนลงขณะที่แป้นพิมพ์ปรากฏขึ้นให้รวมรหัสนี้เข้ากับห้องสมุดนี้ ทำงานเหมือนจับใจ
wonsuc

47

บางครั้ง scrollView.post ไม่ทำงาน

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

แต่ถ้าคุณใช้ scrollView.post ล่าช้ามันจะใช้งานได้อย่างแน่นอน

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

ขอบคุณสำหรับการระบุ โพสต์ล่าช้าเป็นทางออกที่ดีกว่า
Prashant

@Prashant :) :) :)
Ajay Shrestha

1
เพียงจำไว้ว่าคุณต้องกำจัด Runnable ของคุณเมื่อคุณทำกิจกรรมเสร็จแล้ว
FabioR

38

สิ่งที่ดีที่สุดสำหรับฉันคือ

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

ฉันลองสิ่งนี้ แต่อัลกอริทึมที่นี่ผิด โปรดตรวจสอบคำตอบของฉันที่ด้านล่าง
สงบสุข

28

ฉันเพิ่มขึ้นเพื่อทำงานอย่างสมบูรณ์

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

บันทึก

คำตอบนี้เป็นวิธีแก้ปัญหาสำหรับ android เวอร์ชันเก่าจริง ๆ วันนี้postDelayedไม่มีข้อผิดพลาดนั้นอีกแล้วและคุณควรใช้มัน


3
ไม่สูงกว่าสองอัน แต่ใช้งานได้ดีในโทรศัพท์ของฉัน (LG JellyBean 4.1.2 Optimus G)
ยองแจ

9
ทำไมไม่ใช้ scrollView.postDelayed (runnable, 100)
Matt Wolfe

1
@MattWolfe ในเวลานั้นไม่สามารถใช้งานได้ใน Android รุ่นเก่าบางรุ่น แต่วันนี้คำตอบนี้เลิกใช้เลย
ademar111190

4
สำหรับความรักของพระเจ้าให้ใช้ scrollView.postDelayed (runnable, 100)! :)
Alex Lockwood

1
ฉันเพิ่มบันทึกย่อ @AlexLockwood ฉันหวังว่าผู้คนจะใช้postDelayed:)
ademar111190

4

ฉันพยายามประสบความสำเร็จ

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

3

เมื่อยังไม่ได้โหลดมุมมองคุณจะไม่สามารถเลื่อนได้ คุณสามารถทำได้ด้วยการ 'โพสต์' หรือโพสต์การโทรตามที่กล่าวไว้ข้างต้น

มันจะดีกว่าที่จะวางแผนการเลื่อนและทำใน onLayout () ต่อไป รหัสตัวอย่างที่นี่:

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


3

สิ่งหนึ่งที่ควรพิจารณาคือสิ่งที่ไม่ควรตั้งค่า ทำให้แน่ใจว่าคอนโทรลย่อยของคุณโดยเฉพาะคอนโทรล EditText ไม่มีชุดคุณสมบัติ RequestFocus นี่อาจเป็นหนึ่งในคุณสมบัติที่ตีความล่าสุดในโครงร่างและมันจะแทนที่การตั้งค่าแรงโน้มถ่วงบนพาเรนต์ (รูปแบบหรือ ScrollView)


3

นี่คือวิธีอื่นในการเลื่อนไปด้านล่าง

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

การใช้

หากคุณเลื่อนการจัดวางภาพแล้ว

my_scroll_view.scrollToBottom()

หากการเลื่อนหน้าจอของคุณไม่เสร็จสิ้นการจัดวาง (เช่น: คุณเลื่อนไปด้านล่างในonCreateวิธีการกิจกรรม... )

my_scroll_view.post { 
   my_scroll_view.scrollToBottom()          
}

1

ไม่ใช่คำตอบของคำถาม แต่ฉันต้องเลื่อนลงทันทีที่ EditText ได้รับโฟกัส อย่างไรก็ตามคำตอบที่ได้รับการยอมรับจะทำให้ ET เสียการโฟกัสทันที (สำหรับ ScrollView ฉันถือว่า)

วิธีแก้ปัญหาของฉันคือต่อไปนี้:

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

ฉันจริง ๆ แล้วพบว่าการโทรแบบเต็มสเกล

myScrollView.fullScroll(View.FOCUS_DOWN);

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

อาจมีบางอย่างเกี่ยวข้องกับการเปิดใช้งานวิธีการโพสต์ () หลังจากดำเนินการเลื่อนครั้งแรก (ไม่สำเร็จ) ฉันคิดว่าพฤติกรรมนี้เกิดขึ้นหลังจากการเรียกใช้เมธอดก่อนหน้านี้บน myScrollView ดังนั้นคุณสามารถลองเปลี่ยนเมธอด fullScroll () เป็นครั้งแรกด้วยสิ่งอื่นที่อาจเกี่ยวข้องกับคุณ


0

การใช้มีวิธีที่ยอดเยี่ยมอีกวิธีหนึ่งในการทำเช่นนี้กับ Kotlin coroutines ข้อดีของการใช้ coroutine ซึ่งตรงกันข้ามกับตัวจัดการที่มี runnable (post / postDelayed) คือมันไม่ได้ทำให้เธรดมีราคาแพงขึ้นเพื่อดำเนินการล่าช้า

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

สิ่งสำคัญคือต้องระบุ HandlerContext ของ coroutine เป็น UI มิฉะนั้นการดำเนินการล่าช้าอาจไม่ถูกเรียกจากเธรด UI


0

ในกรณีเหล่านั้นใช้เพียงscroll.scrollTo (0, sc.getBottom ())ไม่ทำงานใช้มันโดยใช้ scroll.post

ตัวอย่าง:

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

0

เหตุผลหนึ่งที่เป็นไปได้ว่าทำไมscroll.fullScroll(View.FOCUS_DOWN)อาจไม่ทำงานแม้จะอยู่ใน.post()นั้นคือมุมมองไม่ได้ถูกจัดวางไว้ ในกรณีนี้View.doOnLayout ()อาจเป็นตัวเลือกที่ดีกว่า:

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

หรือมีบางสิ่งที่อธิบายเพิ่มเติมเกี่ยวกับวิญญาณผู้กล้าหาญ: https://chris.banes.dev/2019/12/03/suspending-views/

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.