Android: ScrollView naar beneden forceren

Ik wil dat een ScrollView helemaal onderaan begint. Elke methode?


Antwoord 1, autoriteit 100%

je moet de code in de scroll.post als volgt uitvoeren:

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

Antwoord 2, autoriteit 91%

scroll.fullScroll(View.FOCUS_DOWN)zou ook moeten werken.

Zet dit in een scroll.Post(Runnable run)

Kotlin-code

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

Antwoord 3, autoriteit 33%

scroll.fullScroll(View.FOCUS_DOWN)zal leiden tot de verandering van focus. Dat zal vreemd gedrag met zich meebrengen als er meer dan één focusbare weergaven zijn, bijvoorbeeld twee EditText. Er is een andere manier voor deze vraag.

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

Dit werkt goed.

Kotlin-extensie

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

Antwoord 4, autoriteit 16%

Soms werkt scrollView.post niet

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

MAAR als je scrollView.postDelayed gebruikt, zal het zeker werken

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

Antwoord 5, autoriteit 11%

Wat voor mij het beste werkte, is

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

Antwoord 6, autoriteit 8%

Ik verhoog om perfect te werken.

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

Opmerking

Dit antwoord is een tijdelijke oplossing voor echt oude versies van Android. Vandaag de postDelayedheeft die bug niet meer en je zou hem moeten gebruiken.


Antwoord 7

ik heb dat met succes geprobeerd.

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

Antwoord 8

Als de weergave nog niet is geladen, kunt u niet scrollen. Je kunt het ‘later’ doen met een post- of slaapoproep zoals hierboven, maar dit is niet erg elegant.

Het is beter om de scroll te plannen en dit op de volgende onLayout() te doen. Voorbeeldcode hier:

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


Antwoord 9

Eén ding om te overwegen is wat je NIET moet instellen. Zorg ervoor dat uw onderliggende besturingselementen, met name EditText-besturingselementen, niet de eigenschap RequestFocus hebben. Dit kan een van de laatst geïnterpreteerde eigenschappen in de lay-out zijn en het zal de zwaartekrachtinstellingen op zijn bovenliggende (de lay-out of ScrollView) overschrijven.


Antwoord 10

Hier zijn enkele andere manieren om naar beneden te scrollen

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

Gebruik

Als je scrollview al opgemaakt hebt

my_scroll_view.scrollToBottom()

Als uw scrollview niet volledig is ingedeeld (bijv.: u scrolt naar beneden in de Activity onCreate-methode …)

my_scroll_view.post { 
   my_scroll_view.scrollToBottom()          
}

Antwoord 11

Niet bepaald het antwoord op de vraag, maar ik moest naar beneden scrollen zodra een EditText de focus kreeg. Het geaccepteerde antwoord zou er echter voor zorgen dat de ET ook meteen de focus verliest (naar de ScrollView neem ik aan).

Mijn oplossing was de volgende:

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

Antwoord 12

Ik ontdekte dat het twee keer aanroepen van fullScroll voldoende is:

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

Het kan iets te maken hebben met de activering van de post()-methode direct na het uitvoeren van de eerste (niet-geslaagde) scroll. Ik denk dat dit gedrag optreedt na een eerdere methodeaanroep op myScrollView, dus je kunt proberen de eerste fullScroll()-methode te vervangen door iets anders dat voor jou relevant kan zijn.


Antwoord 13

Er is nog een andere coole manier om dit te doen met Kotlin-coroutines. Het voordeel van het gebruik van een coroutine in tegenstelling tot een Handler met een uitvoerbaar (post/postDelayed) is dat het geen dure thread start om een ​​vertraagde actie uit te voeren.

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

Het is belangrijk om de HandlerContext van de coroutine als UI op te geven, anders wordt de vertraagde actie mogelijk niet aangeroepen vanuit de UI-thread.


Antwoord 14

In dat geval werkt het gebruik van scroll.scrollTo(0, sc.getBottom())niet, gebruik het met scroll.post

Voorbeeld:

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

Antwoord 15

Een mogelijke reden waarom scroll.fullScroll(View.FOCUS_DOWN)misschien niet werkt, zelfs niet verpakt in .post(), is dat de weergave niet is ingedeeld. In dit geval View.doOnLayout()zou een betere optie kunnen zijn:

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

Of iets uitgebreider voor de dappere zielen: https:// chris.banes.dev/2019/12/03/suspending-views/


Antwoord 16

Dit werkt direct. Zonder vertraging.

// wait for the scroll view to be laid out
scrollView.post(new Runnable() {
  public void run() {
    // then wait for the child of the scroll view (normally a LinearLayout) to be laid out
    scrollView.getChildAt(0).post(new Runnable() {
      public void run() {
        // finally scroll without animation
        scrollView.scrollTo(0, scrollView.getBottom());
      }
    }
  }
}

Antwoord 17

Als uw minimale SDK 23 of hoger is, kunt u dit gebruiken:

View childView = findViewById(R.id.your_view_id_in_the_scroll_view)
if(childView != null){
  scrollview.post(() -> scrollview.scrollToDescendant(childView));
}

Antwoord 18

Een combinatie van alle antwoorden deed de truc voor mij:

Uitbreidingsfunctie PostDelayed

private fun ScrollView.postDelayed(
    time: Long = 325, // ms
    block: ScrollView.() -> Unit
) {
    postDelayed({block()}, time)
}

Uitbreiding Functie maatregelScrollHeight

fun ScrollView.measureScrollHeight(): Int {
    val lastChild = getChildAt(childCount - 1)
    val bottom = lastChild.bottom + paddingBottom
    val delta = bottom - (scrollY+ height)
    return delta
}

Uitbreidingsfunctie ScrolltoBottom

fun ScrollView.scrollToBottom() {
    postDelayed {
        smoothScrollBy(0, measureScrollHeight())
    }
}

Houd er rekening mee dat de minimale vertraging minimaal 325 ms moet zijn, anders zal het scrollen buggy zijn (niet helemaal naar beneden scrollen). Hoe groter uw delta tussen de huidige hoogte en de bodem is, hoe groter de vertragingstijd zou moeten zijn.


Antwoord 19

Sommige mensen hier zeiden dat scrollView.post niet werkte.

Als je scrollView.postDelayed niet wilt gebruiken, is een andere optie om een ​​listener te gebruiken. Dit is wat ik deed in een andere use-case:

ViewTreeObserver.OnPreDrawListener viewVisibilityChanged = new ViewTreeObserver.OnPreDrawListener() {
    @Override
    public boolean onPreDraw() {
        if (my_view.getVisibility() == View.VISIBLE) {
            scroll_view.smoothScrollTo(0, scroll_view.getHeight());
        }
        return true;
    }
};

Je kunt het op deze manier aan je weergave toevoegen:

my_view.getViewTreeObserver().addOnPreDrawListener(viewVisibilityChanged);

Other episodes