Como rolar para a parte superior do layout ScrollView longo?

162

Para parte do meu aplicativo, o usuário recebe uma lista de nomes e é solicitado a agrupá-los como acharem melhor.

(Observe que o código do ListView foi copiado literalmente do tutorial do Android Views. Ainda não o personalizei de acordo com minhas necessidades, estou apenas tentando descobrir como fazer isso funcionar.)

O layout básico é um LinearLayout, contendo um ScrollView (chamado "groupsScrollView" no código abaixo), contendo um RelativeLayout. Eu tenho alguns botões e texto e, em seguida, meu ListView abaixo dele, que exibe a lista de nomes. Como tudo isso é mais alto que a área visível da tela, o usuário pode rolar verticalmente para ver tudo.

Tudo isso funciona muito bem, exceto quando a página é carregada, ela é sempre pré-rolada para a parte superior do meu ListView - no meio da página. O texto e os botões que criei que informam ao usuário o que fazer não são visíveis.

Posso pegar a tela e rolar para cima, isso funciona muito bem, mas gostaria que a tela carregasse já tendo sido rolada para o topo. O usuário não precisa rolar para CIMA para ver a parte superior de uma página recém-carregada. Mas tudo o que tentei rolar programaticamente para o topo da tela falhou.

Aqui está o meu método onCreate:

protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    setContentView(R.layout.groups);

    mainScrollView = (ScrollView)findViewById(R.id.groupsScrollView);

    //get the Bundle out of the Intent...
    Bundle extras = getIntent().getExtras();
    mNames = extras.getStringArray("mNames");

    setListAdapter(new ArrayAdapter<String>(this, R.layout.list_item, mNames));

    ListView lv = getListView();
    lv.setTextFilterEnabled(true);

    //This is the line I'm having issues with
    mainScrollView.pageScroll(View.FOCUS_UP);

    lv.setOnItemClickListener(new OnItemClickListener() {
        public void onItemClick(AdapterView<?> parent, View view,
            int position, long id) {
          // When clicked, show a toast with the TextView text
          Toast.makeText(getApplicationContext(), ((TextView) view).getText(),
              Toast.LENGTH_SHORT).show();
        }
      });
}

A linha "mainScrollView.pageScroll (View.FOCUS_UP); é o problema. Não causa um erro, mas parece não fazer nada. Tentei scrollTo (0,0), scrollDirection (View.FOCUS_UP ) e tudo o mais em que posso pensar.

Como não recebo um erro, devo assumir que esses comandos de rolagem estão realmente funcionando, mas estão rolando para a parte superior do ListView, em vez da parte superior do ScrollView ou RelativeLayout que o contém. Isso parece ser confirmado pela própria descrição do Google do método scrollTo (int x, int y), onde eles dizem "Esta versão também restringe a rolagem aos limites do nosso filho".

Portanto, para tornar uma pergunta longa ainda mais longa, como carrego várias visualizações na tela contidas em um ScrollView e depois rumo programaticamente a coisa toda para o topo da página para que o usuário possa interagir com ela?

Obrigado!

Glenn
fonte

Respostas:

264

Experimentar

mainScrollView.fullScroll(ScrollView.FOCUS_UP);

deve funcionar.

roomtek
fonte
Funciona para mim também. : D
Muntasir Aonik 26/10
1
Encontrei ScrollView # fullScroll () alterar o foco atual. Eu testei com o EditText.
illusionJJ
175

Teve o mesmo problema, provavelmente algum tipo de bug.

Até a fullScroll(ScrollView.FOCUS_UP)resposta da outra resposta não funcionou.
A única coisa que funcionou para mim foi ligar scroll_view.smoothScrollTo(0,0)logo após o diálogo ser mostrado.

Mohamed Hafez
fonte
Isso funcionou inicialmente, mas mais tarde, quando tentei fazê-lo várias vezes, essa abordagem não deu resultado satisfatório.
precisa saber é o seguinte
16
Eu resolvo a partir de scroll_view.smoothScrollTo (0,0), quando temos listview ao lado da scrollview naquele momento fullScroll (ScrollView.FOCUS_UP) não funcionará.
Kirtikumar A.
1
scroll_view.smoothScrollTo (0,0) funcionou melhor para mim do que mainScrollView.fullScroll (ScrollView.FOCUS_UP); OBRIGADO!
Marianke
2
Na maioria dos dispositivos, o fullScroll (ScrollView.FOCUS_UP) funcionava, mas no Nexus 5 e nos dispositivos em que o tamanho do texto era aumentado - o fullSsolloll se movia sob a barra de ação, smoothScrollTo (0,0) funcionava melhor em todos os dispositivos.
Jt-gilkeson
Isso também tem a vantagem de fullScroll()manter o item selecionado ainda selecionado após a movimentação. Com fullScroll(), o primeiro item na visualização de rolagem foi novamente selecionado a cada vez no meu caso, independentemente do item selecionado antes da rolagem para cima.
GeertVc
97

Eu tive o mesmo problema e isso foi corrigido. Espero que ajude você.

listView.setFocusable(false);
Miguel Palacios
fonte
3
Esta é a solução correta para gridviews também. Isso acontece quando você tem mais de um elemento de visualização no mesmo grupo de visualizações, especialmente outra exibição de lista no topo da lista ou exibição de grade. Como o adaptador notifica o encadeamento da interface do usuário, a visualização é recriada e rola até o primeiro elemento. Basta chamar listView.setFocusable (false) / gridView.setFocusable (false). Se você fizer isso a partir do arquivo xml, ele não funcionará.
omersem 8/06/16
Essa solução também funcionou no meu caso, eu tinha o RecyclerView dentro do NestedScrollView, de modo que ele rolava automaticamente para baixo. Obrigado cara!
Nilesh Rathore
Eu tive que adicionar isso antes de configurar o adaptador, mas depois isso funciona como um encanto. Obrigado
Comunidade
explicação perfeita !!
Borja López
Obrigado a ambos Miguel e especialmente omersem para a explicação, especialmente a parte sobre como ele vai funcionar se estiver definida em XML, este me salvou algumas dores de cabeça
buradd
53

scrollViewObject.fullScroll(ScrollView.FOCUS_UP)isso funciona bem, mas apenas o problema com esta linha é que, quando os dados são preenchidos no scrollViewObject, foram chamados imediatamente. Você precisa aguardar alguns milissegundos até que os dados sejam preenchidos. Tente este código:

scrollViewObject.postDelayed(new Runnable() {
    @Override
    public void run() {
        scroll.fullScroll(ScrollView.FOCUS_UP);
    }
}, 600);

OU

 scrollViewObject.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
        scrollViewObject.getViewTreeObserver().removeOnGlobalLayoutListener(this);
        scrollViewObject.fullScroll(View.FOCUS_UP);
    }
});
Mohammad Imran
fonte
Eu estava lidando com o mesmo problema em que o scrollview deveria estar rolando para a parte inferior da página, corrigido imediatamente!
Máquina Tribe
1
Em vez de adivinhar o número "mágico" x de milissegundos que você teria que esperar, os objetos View oferecem um método de postagem (Runnable) que você pode usar para publicar a runnable assim que o widget for renderizado na interface do usuário.
21916 Ryan
@ Ryan: pós (Runnable) sempre não funciona para mim no Nexus 5 (Genymotion)
Dika
post (Runnable) pode não funcionar porque, se você buscar dados após a etapa de infoação da visualização, a primeira rolagem para cima funciona e os dados são preenchidos na visualização. Portanto, você deve usar postDelayed (Runnable, dummyMillis) ou scroll.fullScroll (ScrollView.FOCUS_UP) após os processos preenchidos pelos dados.
oguzhan
Sua primeira solução na qual você fornece millis estáticos é uma péssima abordagem.
Malwinder Singh
35

O principal problema de todas essas soluções válidas é que você está tentando mover o rolo de papel quando ele ainda não está desenhado na tela.

Você precisa esperar até a exibição de rolagem aparecer na tela e movê-la para cima com qualquer uma dessas soluções. Esta é uma solução melhor do que um pós-atraso, porque você não se importa com o atraso.

    // Wait until my scrollView is ready
    scrollView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            // Ready, move up
            scrollView.fullScroll(View.FOCUS_UP);
        }
    });
Pelanes
fonte
7
Agradável solução - não se esqueça de remover o Listener global no final do onGlobalLayoutchamado método scrollView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
Nilhcem
30

Muito fácil

    ScrollView scroll = (ScrollView) findViewById(R.id.addresses_scroll);
    scroll.setFocusableInTouchMode(true);
    scroll.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
CommonSenseCode
fonte
3
para mim não funcionou (terceira linha), a solução foi: scroll.fullScroll (View.FOCUS_UP); (com a inclusão de suas 2 primeiras linhas)
medskill 27/01
@medskill, Oi, você escreveu isso no seu arquivo xml? Eu acho que isso funciona apenas em onCreate().
desconhecido 22/03/17
@ imknownJ.Kimu funciona para mim no arquivo xml
Paglian
Isso funcionou para mim. Você precisa da segunda e da terceira linha. Não funcionaria no XML para mim.
ET
2
Eu te beijaria se pudesse! Passado 1-2 horas sobre isso. O melhor quando se espera que duas visualizações de lista sejam carregadas e não se quer focar nelas. Adicionado ao onResume ().
John T
24

Enfrentei o mesmo problema Quando estou usando o Scrollview dentro do View Flipper ou Dialog, esse caso scrollViewObject.fullScroll(ScrollView.FOCUS_UP)retorna falso, para que o caso scrollViewObject.smoothScrollTo(0, 0)seja trabalhado para mim

Scroll Focus Top

sravan
fonte
19
 final ScrollView scrollview = (ScrollView)findViewById(R.id.selected_place_layout_scrollview);

         scrollview.post(new Runnable() { 
                public void run() { 
                    scrollview.scrollTo(0, 0); 
                } 
            }); 
Mladen Rakonjac
fonte
9
runOnUiThread( new Runnable(){
   @Override
   public void run(){
      mainScrollView.fullScroll(ScrollView.FOCUS_UP);
   }
}
traeper
fonte
9

Isso é trabalhado para mim

scroll_view.smoothScrollTo(0,0); // scroll to top of screen
Pankaj Talaviya
fonte
6

Isso é forçar rolagem para scrollview :

            scrollView.post(new Runnable() {
                @Override
                public void run() {
                    scrollView.scrollTo(0, 0);
                    scrollView.pageScroll(View.FOCUS_UP);
                    scrollView.smoothScrollTo(0,0);
                }
            });
Hadi Note
fonte
4
scrollView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
        // Ready, move up
        scrollView.fullScroll(View.FOCUS_UP);
    }
});

fonte
1

Corrigi meu problema no Kotlin assim:

scrollview.isFocusableInTouchMode = true
scrollview.fullScroll(View.FOCUS_UP)
scrollview.smoothScrollTo(0,0)
MaK
fonte
0
@SuppressWarnings({ "deprecation", "unchecked" })
public void swipeTopToBottom(AppiumDriver<MobileElement> driver) 
                    throws InterruptedException {
       Dimension dimensions = driver.manage().window().getSize();
        Double screenHeightStart = dimensions.getHeight() * 0.30;
        int scrollStart = screenHeightStart.intValue();
        System.out.println("s="+scrollStart);
        Double screenHeightEnd = dimensions.getHeight()*0.90;
        int scrollEnd = screenHeightEnd.intValue();
        driver.swipe(0,scrollStart,0,scrollEnd,2000);
        CommonUtils.threadWait(driver, 3000);
    }
Ajeet Gour
fonte
este será executado com certeza,
Ajeet Gour
Forneça uma breve explicação de como esta resposta resolve o problema.
Ayberk Özgür