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.