Posso rolar um ScrollView programaticamente no Android?

145

Existe alguma maneira de rolar um ScrollViewprogramaticamente para uma determinada posição?

Eu criei uma dinâmica TableLayoutque é colocada em a ScrollView. Então, eu quero que em uma ação específica (como clicar em um botão etc.), a linha específica role automaticamente para a posição superior.

É possível?

Arun Badole
fonte

Respostas:

165
ScrollView sv = (ScrollView)findViewById(R.id.scrl);
sv.scrollTo(0, sv.getBottom());

ou

sv.scrollTo(5, 10);

Android
fonte
43
Combinando a resposta de Ercu e um comentário feito sobre ele, a melhor maneira parece ser:mScrollView.post(new Runnable() { public void run() { mScrollView.fullScroll(View.FOCUS_DOWN); } });
sparrowt
2
scrollTo () não produzirá resultado de desejo. Deve-se usar o fullScroll () #
Amit Yadav
3
Rolagem mais agradável é com efeito natural: sv.smoothScrollTo (5, 10)
ivan.panasiuk
205

A resposta da Pragna nem sempre funciona, tente o seguinte:

mScrollView.post(new Runnable() { 
        public void run() { 
             mScrollView.scrollTo(0, mScrollView.getBottom());
        } 
});

ou

mScrollView.post(new Runnable() { 
        public void run() { 
             mScrollView.fullScroll(mScrollView.FOCUS_DOWN);
        } 
});

se você quiser rolar para começar

mScrollView.post(new Runnable() { 
        public void run() { 
             mScrollView.fullScroll(mScrollView.FOCUS_UP);
        } 
});
ercu
fonte
28
Eu usei mScrollView.fullScroll(mScrollView.FOCUS_DOWN);com sucesso.
22712 amcc
3
Eu posso confirmar as descobertas de Vanthel. mScrollView.fullScroll em um post executável fez o truque.
AlanKley
1
Excelente! De fato, sem o Runnable, não funcionou. Agora funciona! :)
Regis_AG
5
@HiteshDhamshaniya Se você quiser uma rolagem suave, tente mScrollView.smoothScrollTo(0, mScrollView.getBottom());.
9608 Mike
1
Por que precisa postaqui?
Liuting
35

Eu queria que o scrollView rolasse diretamente após onCreateView () (não depois, por exemplo, de um clique no botão). Para fazê-lo funcionar, eu precisava usar um ViewTreeObserver:

mScrollView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            mScrollView.post(new Runnable() {
                public void run() {
                    mScrollView.fullScroll(View.FOCUS_DOWN);
                }
            });
        }
    });

Mas lembre-se de que isso será chamado sempre que algo for projetado (por exemplo, se você definir uma exibição como invisível ou semelhante); portanto, não se esqueça de remover este ouvinte se você não precisar mais dele com:

public void removeGlobalOnLayoutListener (ViewTreeObserver.OnGlobalLayoutListener victim) no SDK Nív. <16

ou

public void removeOnGlobalLayoutListener (ViewTreeObserver.OnGlobalLayoutListener victim) no SDK Nvl> = 16

Patrick Favre
fonte
23

Há muitas boas respostas aqui, mas quero apenas acrescentar uma coisa. Às vezes, você deseja rolar o ScrollView para uma visualização específica do layout, em vez de uma rolagem completa para cima ou para baixo.

Um exemplo simples: em um formulário de registro, se o usuário tocar no botão "Inscrição" quando um texto de edição do formulário não estiver preenchido, você deverá rolar para o texto de edição específico para informar ao usuário que ele deve preencher esse campo.

Nesse caso, você pode fazer algo assim:

scrollView.post(new Runnable() { 
        public void run() { 
             scrollView.scrollTo(0, editText.getBottom());
        } 
});

ou, se você desejar uma rolagem suave em vez de uma rolagem instantânea:

scrollView.post(new Runnable() { 
            public void run() { 
                 scrollView.smoothScrollTo(0, editText.getBottom());
            } 
    });

Obviamente, você pode usar qualquer tipo de visualização em vez de Editar texto. Observe que getBottom () retorna as coordenadas da vista com base em seu layout pai, portanto todas as vistas usadas no ScrollView devem ter apenas um pai (por exemplo, um Layout Linear).

Se você tem vários pais dentro do filho do ScrollView, a única solução que encontrei é chamar requestChildFocus na exibição pai:

editText.getParent().requestChildFocus(editText, editText);

mas, neste caso, você não pode ter uma rolagem suave.

Espero que esta resposta possa ajudar alguém com o mesmo problema.

Mattia Ruggiero
fonte
1
@JohnT Fico feliz que ajudou você :)
Mattia Ruggiero
20

Use algo como isto:

mScrollView.scrollBy(10, 10);

ou

mScrollView.scrollTo(10, 10);
Srichand Yella
fonte
9

Tente usar o scrollTométodo Mais informações

bluefalcon
fonte
8

Se você quiser rolar instantaneamente, poderá usar:

ScrollView scroll= (ScrollView)findViewById(R.id.scroll);
scroll.scrollTo(0, scroll.getBottom());

            OR

scroll.fullScroll(View.FOCUS_DOWN);

            OR

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

Ou se você quiser rolar suavemente e lentamente para poder usar isso:

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();
    }
Maddy
fonte
o que esse catchbloco faz?
John Sardinha
1
O bloco catch é capturar exceções durante a rolagem, se houver.
Maddy
5

** para rolar até a altura desejada. Eu vim com uma boa solução **

                scrollView.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        scrollView.scrollBy(0, childView.getHeight());
                    }
                }, 100);
Vikas Chauhan
fonte
4

Eu consegui isso para rolar para a parte inferior de um ScrollView (com um TextView dentro):

(Eu coloquei isso em um método que atualiza o TextView)

final ScrollView myScrollView = (ScrollView) findViewById(R.id.myScroller);
    myScrollView.post(new Runnable() {
    public void run() {
        myScrollView.fullScroll(View.FOCUS_DOWN);
    }
});
Ohiovr
fonte
4

Sim você pode.

Digamos que você tenha um Layoute, dentro disso, você tem muitos Views. Portanto, se você desejar rolar para qualquer Viewprogramaticamente, precisará escrever o seguinte trecho de código:

Por exemplo:

content_main.xml

<ScrollView
    android:id="@+id/scrollView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <Button
            android:id="@+id/btn"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

        <TextView
            android:id="@+id/txtView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

    </LinearLayout>
</ScrollView>

MainActivity.java

ScrollView scrollView = (ScrollView) findViewById(R.id.scrollView);
Button btn = (Button) findViewById(R.id.ivEventBanner);
TextView txtView = (TextView) findViewById(R.id.ivEditBannerImage);

Se você quiser rolar para um específico View, digamos txtview , neste caso, basta escrever:

scrollView.smoothScrollTo(txtView.getScrollX(),txtView.getScrollY());

E você terminou.

Pankaj Lilan
fonte
3

Nota: se você já estiver em um tópico, precisará criar um novo tópico, ou não será rolado uma nova altura longa até o final completo (para mim). Por exemplo:

void LogMe(final String s){
    runOnUiThread(new Runnable() {
        public void run() {
            connectionLog.setText(connectionLog.getText() + "\n" + s);
            final ScrollView sv = (ScrollView)connectLayout.findViewById(R.id.scrollView);
            sv.post(new Runnable() {
                public void run() {
                    sv.fullScroll(sv.FOCUS_DOWN);
                    /*
                    sv.scrollTo(0,sv.getBottom());
                    sv.scrollBy(0,sv.getHeight());*/
                }
            });
        }
    });
}
djdance
fonte
3

Adicionando outra resposta que não envolve coordenadas.

Isso trará a visualização desejada para o foco (mas não para a posição superior):

  yourView.getParent().requestChildFocus(yourView,yourView);

public void RequestChildFocus (Ver filho, Ver focado)

child - O filho deste ViewParent que deseja foco. Essa visualização conterá a visualização focada. Não é necessariamente a visão que realmente tem foco.

focado - A visão de descendente de criança que realmente tem foco

Swas_99
fonte
Exatamente o que eu precisava, obrigado. Primeiro, solicite o foco para você rolar a exibição e depois scrollView.smoothScrollTo (0, scrollView.getChildAt (0) .getBottom ());
Vulovic Vukasin
3

apenas rolagem de página:

ScrollView sv = (ScrollView) findViewById(your_scroll_view);
sv.pageScroll(View.FOCUS_DOWN);
Kirill Vashilo
fonte
2

Todo mundo está postando respostas tão complicadas.

Encontrei uma resposta fácil, para rolar para baixo, muito bem:

final ScrollView myScroller = (ScrollView) findViewById(R.id.myScrollerView);

// Scroll views can only have 1 child, so get the first child's bottom,
// which should be the full size of the whole content inside the ScrollView
myScroller.smoothScrollTo( 0, myScroller.getChildAt( 0 ).getBottom() );

E, se necessário, você pode colocar a segunda linha de código acima em um executável:

myScroller.post( new Runnable() {
    @Override
    public void run() {
        myScroller.smoothScrollTo( 0, myScroller.getChildAt( 0 ).getBottom() );
    }
}

Levei muita pesquisa e brincadeira para encontrar esta solução simples. Espero que ajude você também! :)

Nalorin
fonte
1

Eu estava usando o Runnable com sv.fullScroll (View.FOCUS_DOWN); Funciona perfeitamente para o problema imediato, mas esse método faz com que o ScrollView retire o foco da tela inteira; se você fizer o AutoScroll sempre, nenhum EditText poderá receber informações do usuário; minha solução foi usar um código diferente. sob o executável:

sv.scrollTo (0, sv.getBottom () + sv.getScrollY ());

fazendo o mesmo sem perder o foco em visões importantes

saudações.

Sebasu
fonte
0

está funcionando para mim

mScrollView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            mScrollView.post(new Runnable() {
                public void run() {
                    mScrollView.fullScroll(View.FOCUS_DOWN);
                }
            });
        }
    });
ali asadi
fonte
0
private int totalHeight = 0;

ViewTreeObserver ScrollTr = loutMain.getViewTreeObserver();
ScrollTr.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
            loutMain.getViewTreeObserver().removeGlobalOnLayoutListener(this);
        } else {
            loutMain.getViewTreeObserver().removeOnGlobalLayoutListener(this);
        }
        TotalHeight = loutMain.getMeasuredHeight();

    }
});

scrollMain.smoothScrollTo(0, totalHeight);
P. Patel
fonte
0
I had to create Interface

public interface ScrollViewListener {
    void onScrollChanged(ScrollViewExt scrollView, 
                         int x, int y, int oldx, int oldy);
}    

import android.content.Context;
import android.util.AttributeSet;
import android.widget.ScrollView;

public class CustomScrollView extends ScrollView {
    private ScrollViewListener scrollViewListener = null;
    public ScrollViewExt(Context context) {
        super(context);
    }

    public CustomScrollView (Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public CustomScrollView (Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public void setScrollViewListener(ScrollViewListener scrollViewListener) {
        this.scrollViewListener = scrollViewListener;
    }

    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        super.onScrollChanged(l, t, oldl, oldt);
        if (scrollViewListener != null) {
            scrollViewListener.onScrollChanged(this, l, t, oldl, oldt);
        }
    }
}




<"Your Package name ".CustomScrollView 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/scrollView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:focusableInTouchMode="true"
    android:scrollbars="vertical">

    private CustomScrollView scrollView;

scrollView = (CustomScrollView)mView.findViewById(R.id.scrollView);
        scrollView.setScrollViewListener(this);


    @Override
    public void onScrollChanged(ScrollViewExt scrollView, int x, int y, int oldx, int oldy) {
        // We take the last son in the scrollview
        View view = (View) scrollView.getChildAt(scrollView.getChildCount() - 1);
        int diff = (view.getBottom() - (scrollView.getHeight() + scrollView.getScrollY()));

        // if diff is zero, then the bottom has been reached
        if (diff == 0) {
                // do stuff
            //TODO keshav gers
            pausePlayer();
            videoFullScreenPlayer.setVisibility(View.GONE);

        }
    }
Keshav Gera
fonte