O ViewPager2
(link em inglês) é uma versão aprimorada da biblioteca ViewPager
que oferece
funcionalidade aprimorada e aborda dificuldades comuns com o uso de ViewPager
.
Caso seu app já use o ViewPager
, leia esta página para saber mais sobre
migrando para ViewPager2
.
Se você quiser usar ViewPager2
no seu app e não estiver usando
ViewPager
, leia Deslizar entre fragmentos usando
ViewPager2 e Criar visualizações deslizáveis com
usando o ViewPager2 para mais
informações imprecisas ou inadequadas.
Benefícios da migração para o ViewPager2
O principal motivo para migrar é que ViewPager2
está recebendo dados
e não o ViewPager
. No entanto, o ViewPager2
também oferece
e muitas outras vantagens específicas.
Compatibilidade com orientação vertical
O ViewPager2
oferece suporte à paginação vertical, além da horizontal tradicional.
paginação. É possível ativar a paginação vertical para um elemento ViewPager2
configurando o
Atributo android:orientation
:
<androidx.viewpager2.widget.ViewPager2
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/pager"
android:orientation="vertical" />
Também é possível definir esse atributo de maneira programática usando o método setOrientation() (link em inglês) .
Suporte da direita para a esquerda
O ViewPager2
é compatível com paginação da direita para a esquerda (RTL, na sigla em inglês). A paginação RTL está ativada
de forma automática, quando apropriado, com base na localidade, mas também é possível
Para ativar a paginação RTL para um elemento ViewPager2
, defina o
Atributo android:layoutDirection
:
<androidx.viewpager2.widget.ViewPager2
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/pager"
android:layoutDirection="rtl" />
Também é possível definir esse atributo de maneira programática usando o método setLayoutDirection() (link em inglês) .
Coleções de fragmentos modificáveis
O ViewPager2
oferece suporte à paginação por uma coleção modificável de fragmentos,
chamar
notifyDatasetChanged()
para atualizar a IU quando a coleção subjacente é alterada.
Isso significa que seu app pode modificar dinamicamente a coleção de fragmentos em
ambiente de execução, e ViewPager2
exibirá corretamente a coleção modificada.
DiffUtil
O ViewPager2
foi criado no RecyclerView
,
ou seja, ele tem acesso
Utilitário DiffUtil
. Isso gera vários benefícios, mas o mais importante é que
Os objetos ViewPager2
aproveitam nativamente as animações de alteração do conjunto de dados.
da classe RecyclerView
.
Migrar seu app para o ViewPager2
Siga estas etapas para atualizar objetos ViewPager
no seu app para ViewPager2
:
Atualizar arquivos de layout XML
Primeiro, substitua os elementos ViewPager
nos arquivos de layout XML por
Elementos ViewPager2
:
<!-- A ViewPager element -->
<android.support.v4.view.ViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<!-- A ViewPager2 element -->
<androidx.viewpager2.widget.ViewPager2
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Atualizar as classes do adaptador
Ao usar ViewPager
, foi necessário estender a classe do adaptador que
novas páginas fornecidas ao objeto. Dependendo do caso de uso, a ViewPager
foi usada
três classes abstratas diferentes. O ViewPager2
usa apenas duas classes abstratas.
Para cada objeto ViewPager
que você está convertendo em um objeto ViewPager2
,
Atualize a classe do adaptador para estender a classe abstrata adequada da seguinte maneira:
- Quando
ViewPager
usarPagerAdapter
para paginar visualizações, useRecyclerView.Adapter
comViewPager2
. - Quando
ViewPager
usouFragmentPagerAdapter
para paginar um pequeno, número fixo de fragmentos, o uso deFragmentStateAdapter
comViewPager2
. - Quando
ViewPager
usouFragmentStatePagerAdapter
para percorrer uma número grande ou desconhecido de fragmentos, useFragmentStateAdapter
comViewPager2
.
Parâmetros do construtor
Classes de adaptador baseadas em fragmentos herdadas de FragmentPagerAdapter
ou
FragmentStatePagerAdapter
sempre aceitam um único objeto FragmentManager
.
como um parâmetro construtor. Quando você estende FragmentStateAdapter
para um
ViewPager2
, você tem as seguintes opções para o construtor
parâmetros:
- O objeto
FragmentActivity
ouFragment
em que oViewPager2
reside. Na maioria dos casos, essa é a melhor opção. - Um objeto
FragmentManager
e um objetoLifecycle
.
As classes de adaptador baseadas em visualização herdadas diretamente de RecyclerView.Adapter
fazem
não exigem um parâmetro construtor.
Modificar métodos
Suas classes de adaptador também precisam substituir métodos diferentes para ViewPager2
.
do que com ViewPager
:
- Em vez de
getCount()
, modifiquegetItemCount()
. Além do nome, esse método não muda. - Em vez de
getItem()
, substituacreateFragment()
na abordagem baseada em fragmento adaptador. Verifique se o novo métodocreateFragment()
sempre fornece uma nova instância de fragmento sempre que a função é chamada em vez de reutilizar instâncias.
Resumo
Em resumo, para converter uma classe de adaptador ViewPager
para uso com ViewPager2
,
faça as seguintes alterações:
- Mude a superclasse para
RecyclerView.Adapter
para percorrer visualizações ouFragmentStateAdapter
para percorrer fragmentos. - Altere os parâmetros do construtor em classes de adaptador baseadas em fragmento.
- Modifique
getItemCount()
em vez degetCount()
. - Substituir
createFragment()
em vez degetItem()
no adaptador baseado em fragmento classes.
Kotlin
// A simple ViewPager adapter class for paging through fragments class ScreenSlidePagerAdapter(fm: FragmentManager) : FragmentStatePagerAdapter(fm) { override fun getCount(): Int = NUM_PAGES override fun getItem(position: Int): Fragment = ScreenSlidePageFragment() } // An equivalent ViewPager2 adapter class class ScreenSlidePagerAdapter(fa: FragmentActivity) : FragmentStateAdapter(fa) { override fun getItemCount(): Int = NUM_PAGES override fun createFragment(position: Int): Fragment = ScreenSlidePageFragment() }
Java
// A simple ViewPager adapter class for paging through fragments public class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter { public ScreenSlidePagerAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int position) { return new ScreenSlidePageFragment(); } @Override public int getCount() { return NUM_PAGES; } } // An equivalent ViewPager2 adapter class private class ScreenSlidePagerAdapter extends FragmentStateAdapter { public ScreenSlidePagerAdapter(FragmentActivity fa) { super(fa); } @Override public Fragment createFragment(int position) { return new ScreenSlidePageFragment(); } @Override public int getItemCount() { return NUM_PAGES; } }
Refatorar interfaces do TabLayout
O ViewPager2
introduz alterações na integração do TabLayout
. Se você
usa uma ViewPager
com um objeto TabLayout
para mostrar conteúdo horizontal.
guias para navegação, será necessário refatorar o objeto TabLayout
para
com o ViewPager2
.
A conta TabLayout
foi dissociada do ViewPager2
e agora está disponível como parte do
Componentes do Material Design. Isso significa que, para usá-lo, você precisa adicionar
a dependência apropriada para seu arquivo build.gradle
:
Groovy
implementation "com.google.android.material:material:1.1.0-beta01"
Kotlin
implementation("com.google.android.material:material:1.1.0-beta01")
Também é necessário mudar a localização do elemento TabLayout
na hierarquia de
seu arquivo de layout XML. Com ViewPager
, o elemento TabLayout
é declarado como uma
filho do elemento ViewPager
. mas com ViewPager2
, o elemento TabLayout
é declarado diretamente acima do elemento ViewPager2
, no mesmo nível:
<!-- A ViewPager element with a TabLayout -->
<androidx.viewpager.widget.ViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.tabs.TabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</androidx.viewpager.widget.ViewPager>
<!-- A ViewPager2 element with a TabLayout -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.google.android.material.tabs.TabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
</LinearLayout>
Por fim, atualize o código que anexa o objeto TabLayout
ao
objeto ViewPager
. Enquanto TabLayout
usa o próprio setupWithViewPager()
para integrar com ViewPager
, ele exige um TabLayoutMediator
para integração com ViewPager2
.
O objeto TabLayoutMediator
também processa a tarefa de gerar títulos de páginas
para o objeto TabLayout
, o que significa que a classe do adaptador não precisa
substituir getPageTitle()
:
Kotlin
// Integrating TabLayout with ViewPager class CollectionDemoFragment : Fragment() { ... override fun onViewCreated(view: View, savedInstanceState: Bundle?) { val tabLayout = view.findViewById(R.id.tab_layout) tabLayout.setupWithViewPager(viewPager) } ... } class DemoCollectionPagerAdapter(fm: FragmentManager) : FragmentStatePagerAdapter(fm) { override fun getCount(): Int = 4 override fun getPageTitle(position: Int): CharSequence { return "OBJECT ${(position + 1)}" } ... } // Integrating TabLayout with ViewPager2 class CollectionDemoFragment : Fragment() { ... override fun onViewCreated(view: View, savedInstanceState: Bundle?) { val tabLayout = view.findViewById(R.id.tab_layout) TabLayoutMediator(tabLayout, viewPager) { tab, position -> tab.text = "OBJECT ${(position + 1)}" }.attach() } ... }
Java
// Integrating TabLayout with ViewPager public class CollectionDemoFragment extends Fragment { ... @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { TabLayout tabLayout = view.findViewById(R.id.tab_layout); tabLayout.setupWithViewPager(viewPager); } ... } public class DemoCollectionPagerAdapter extends FragmentStatePagerAdapter { ... @Override public int getCount() { return 4; } @Override public CharSequence getPageTitle(int position) { return "OBJECT " + (position + 1); } ... } // Integrating TabLayout with ViewPager2 public class CollectionDemoFragment : Fragment() { ... @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { TabLayout tabLayout = view.findViewById(R.id.tab_layout); new TabLayoutMediator(tabLayout, viewPager, (tab, position) -> tab.setText("OBJECT " + (position + 1)) ).attach(); } ... }
Suporte a elementos roláveis aninhados
ViewPager2
não oferece suporte nativo a visualizações de rolagem aninhadas nos casos em que o
visualização de rolagem tem a mesma orientação que o objeto ViewPager2
que contém
reimplantá-lo. Por exemplo, a rolagem não funcionaria para uma visualização de rolagem vertical dentro de uma
objeto ViewPager2
orientado verticalmente.
Para oferecer suporte a uma visualização de rolagem dentro de um objeto ViewPager2
com a mesma orientação, faça o seguinte:
você precisa chamar
requestDisallowInterceptTouchEvent()
no objeto ViewPager2
quando você
esperar rolar o elemento aninhado. A rolagem aninhada do ViewPager2
exemplo (link em inglês) demonstra uma maneira de resolver esse problema com uma
layout de wrapper personalizado.
Outros recursos
Para saber mais sobre o ViewPager2
, consulte os recursos adicionais a seguir.
Amostras
- Amostras do ViewPager2 no GitHub (em inglês)
Vídeos
- Virando a página: como migrar para o ViewPager2 (Conferência de Desenvolvedores Android '19)