Android: ScrollView força para baixo


200

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


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

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

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

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

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

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.


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

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


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


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

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

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


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.


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

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.