Android: ScrollView força para baixo

200

Gostaria que um ScrollView iniciasse na parte inferior. Algum método?

Noah Seidman
fonte
1
Eu acho que é apenas scrollTo (), sim, acabei de verificar os documentos de desenvolvimento para o ScrollView. Mole-mole.
Noah Seidman

Respostas:

274

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)
}
CommonsWare
fonte
6
Isso parece não fazer nada, alguma sugestão? Eu tentei no onCreate e mais tarde no onClick de um botão.
RichardJohnn
Parece não funcionar para mudar a orientação. Caso contrário, está funcionando.
Prashant
1
Isso não funciona se o tamanho do layout foi alterado antes de chamá-lo. Ele precisa ser publicado.
MLProgrammer-CiM
2
Isso e abaixo, não funcionará até que você dedique algum tempo para que a exibição seja totalmente inflada, simplificando a resposta ademar. scrollView.postDelayed (new Runnable () {@Override public void run () {scrollView.fullScroll (View.FOCUS_UP // Ou para baixo);}}, 1000);
EngineSense
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. Verifique outra solução que forneço na parte inferior.
peacepassion
332

você deve executar o código dentro do scroll.post assim:

scroll.post(new Runnable() {            
    @Override
    public void run() {
           scroll.fullScroll(View.FOCUS_DOWN);              
    }
});
hungson175
fonte
4
há alguma forma, sem perder o foco elemento atual, quando eu fizer isso eu perder o foco do meu elemento atual (diferente de scrollview)
rkmax
2
Isso é necessário apenas nos casos em que o layout ainda não foi medido e estruturado (por exemplo, se você o executar no onCreate). Em casos como pressionar um botão, .post () não é necessário.
Patrick Boos
12
Se você não quer se concentrar no ScrollView, você pode usar scroll.scrollTo(0, scroll.getHeight());para saltar para a parte inferior, ou scroll.smoothScrollTo(0, scroll.getHeight());para uma rolagem mais suave
yuval
Esse código não é um possível vazamento de memória? É criado um Runnable anônimo que mantém uma referência a uma exibição de atividade (rolagem). Se a atividade for destruída enquanto o executável estiver executando sua tarefa, vazará uma referência à visualização de rolagem, não?
1911
Em Kotlin:scrollView.post { scrollView.fullScroll(View.FOCUS_DOWN) }
Albert Vila Calvo
94

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)
}
paz
fonte
Tão feliz que não tive que perder mais tempo com isso. Apenas o que eu precisava
Alexandre G
6
Isso deveria ter mais votos positivos. É a melhor resposta de longe.
Eric Lange
1
Esta é a melhor resposta aqui apresentada.
ponteiro void
1
Tentei de tudo nesta página, mesmo o material abaixo disso. Essa foi a única coisa que funcionou e não faz com que meu EditText perca o foco. Obrigado.
Joel
Se você precisar rolar para baixo enquanto o teclado estiver aparecendo, combine esse código com esta biblioteca . Funciona como um encanto.
wonsuc
47

À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);
Ajay Shrestha
fonte
obrigado pela identificação. postDelayed é a melhor solução.
Prashant
@Prashant :) :) :)
Ajay Shrestha
1
Basta lembrar que você precisa se desfazer do seu Runnable quando terminar a atividade
FabioR
38

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());
     }
});
https
fonte
Eu tentei isso, mas o algoritmo aqui está errado. Verifique minha resposta na parte inferior, por favor.
peacepassion
28

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 postDelayedbug não tem mais e você deve usá-lo.

ademar111190
fonte
3
Não acima de dois, mas isso funciona bem no meu telefone (LG JellyBean 4.1.2 Optimus G).
29413 Youngjae
9
Por que não usar scrollView.postDelayed (executável, 100)?
Matt Wolfe
1
O @MattWolfe na época não funciona em algumas versões antigas do Android. Hoje, porém, essa resposta está obsoleta.
ademar111190
4
Pelo amor de Deus, use scrollView.postDelayed (executável, 100)! :)
Alex Lockwood
1
Eu adicionei uma nota @AlexLockwood Espero que as pessoas usam o postDelayed:)
ademar111190
4

Eu tentei esse sucesso.

scrollView.postDelayed(new Runnable() {
    @Override
    public void run() {
        scrollView.smoothScrollTo(0, scrollView.getHeight());
    }
}, 1000);
Yusuf Yaşar
fonte
3

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:

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

Frank
fonte
3

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

Epsilon3
fonte
3

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 onCreatemétodo Activity ...)

my_scroll_view.post { 
   my_scroll_view.scrollToBottom()          
}
Phan Van Linh
fonte
1

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();
        }
    }
});
Teo Inke
fonte
1

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ê.

BarLr
fonte
0

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.

Pestião
fonte
0

Nesse caso, estava usando apenas scroll.scrollTo (0, sc.getBottom ()) não funciona, use-o usando scroll.post

Exemplo:

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