Gostaria que um ScrollView iniciasse na parte inferior. Algum método?
Gostaria que um ScrollView iniciasse na parte inferior. Algum método?
Respostas:
scroll.fullScroll(View.FOCUS_DOWN)
também deve funcionar.
Coloque isso em um scroll.Post(Runnable run)
Código Kotlin
scrollView.post {
scrollView.fullScroll(View.FOCUS_DOWN)
}
você deve executar o código dentro do scroll.post assim:
scroll.post(new Runnable() {
@Override
public void run() {
scroll.fullScroll(View.FOCUS_DOWN);
}
});
scroll.scrollTo(0, scroll.getHeight());
para saltar para a parte inferior, ou scroll.smoothScrollTo(0, scroll.getHeight());
para uma rolagem mais suave
scrollView.post { scrollView.fullScroll(View.FOCUS_DOWN) }
scroll.fullScroll(View.FOCUS_DOWN)
levará à mudança de foco. Isso trará algum comportamento estranho quando houver mais de uma exibição focalizável, por exemplo, dois EditText. Existe outro caminho para essa pergunta.
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);
Isso funciona bem.
Extensão Kotlin
fun ScrollView.scrollToBottom() {
val lastChild = getChildAt(childCount - 1)
val bottom = lastChild.bottom + paddingBottom
val delta = bottom - (scrollY+ height)
smoothScrollBy(0, delta)
}
Às vezes, scrollView.post não funciona
scrollView.post(new Runnable() {
@Override
public void run() {
scrollView.fullScroll(ScrollView.FOCUS_DOWN);
}
});
MAS se você usar scrollView.postDelayed, ele definitivamente funcionará
scrollView.postDelayed(new Runnable() {
@Override
public void run() {
scrollView.fullScroll(ScrollView.FOCUS_DOWN);
}
},1000);
O que funcionou melhor para mim é
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());
}
});
Eu incremento para funcionar perfeitamente.
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();
}
Nota
Esta resposta é uma solução alternativa para versões realmente antigas do Android. Hoje o postDelayed
bug não tem mais e você deve usá-lo.
postDelayed
:)
Eu tentei esse sucesso.
scrollView.postDelayed(new Runnable() {
@Override
public void run() {
scrollView.smoothScrollTo(0, scrollView.getHeight());
}
}, 1000);
Quando a visualização ainda não está carregada, você não pode rolar. Você pode fazer isso mais tarde com uma chamada pós-sono ou de suspensão, conforme descrito acima, mas isso não é muito elegante.
É melhor planejar a rolagem e fazê-lo no próximo onLayout (). Exemplo de código aqui:
Uma coisa a considerar é o que NÃO definir. Verifique se os controles filho, principalmente os controles EditText, não possuem a propriedade RequestFocus definida. Essa pode ser uma das últimas propriedades interpretadas no layout e substituirá as configurações de gravidade em seus pais (o layout ou o ScrollView).
Aqui estão algumas outras maneiras de rolar para baixo
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()
}
Usando
Se você visualizar a rolagem já definida
my_scroll_view.scrollToBottom()
Se sua visualização de rolagem não estiver concluída (por exemplo: você role para baixo no onCreate
método Activity ...)
my_scroll_view.post {
my_scroll_view.scrollToBottom()
}
Não é exatamente a resposta para a pergunta, mas eu precisava rolar para baixo assim que um EditText conseguisse o foco. No entanto, a resposta aceita faria com que o ET também perdesse o foco imediatamente (para o ScrollView, presumo).
Minha solução alternativa foi a seguinte:
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();
}
}
});
Na verdade, eu achei que chamar fullScroll duas vezes faz o truque:
myScrollView.fullScroll(View.FOCUS_DOWN);
myScrollView.post(new Runnable() {
@Override
public void run() {
myScrollView.fullScroll(View.FOCUS_DOWN);
}
});
Pode ter algo a ver com a ativação do método post () logo após executar o primeiro deslocamento (sem êxito). Acho que esse comportamento ocorre após qualquer chamada de método anterior no myScrollView, para que você possa tentar substituir o primeiro método fullScroll () por qualquer outra coisa que possa ser relevante para você.
O uso de outra maneira legal de fazer isso com as corotinas Kotlin. A vantagem de usar uma corotina oposta a um manipulador com um executável (post / postDelayed) é que ele não aciona um encadeamento caro para executar uma ação atrasada.
launch(UI){
delay(300)
scrollView.fullScroll(View.FOCUS_DOWN)
}
É importante especificar o HandlerContext da corotina como interface do usuário; caso contrário, a ação atrasada poderá não ser chamada a partir do encadeamento da interface do usuário.
Uma possível razão pela qual scroll.fullScroll(View.FOCUS_DOWN)
talvez não funcione, .post()
é que a visão não é apresentada. Nesse caso View.doOnLayout () poderia ser uma opção melhor:
scroll.doOnLayout(){
scroll.fullScroll(View.FOCUS_DOWN)
}
Ou, algo mais elaborado para as almas corajosas: https://chris.banes.dev/2019/12/03/suspending-views/