Migrar do ViewPager para o ViewPager2

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:

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:

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(), modifique getItemCount(). Além do nome, esse método não muda.
  • Em vez de getItem(), substitua createFragment() na abordagem baseada em fragmento adaptador. Verifique se o novo método createFragment() 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:

  1. Mude a superclasse para RecyclerView.Adapter para percorrer visualizações ou FragmentStateAdapter para percorrer fragmentos.
  2. Altere os parâmetros do construtor em classes de adaptador baseadas em fragmento.
  3. Modifique getItemCount() em vez de getCount().
  4. Substituir createFragment() em vez de getItem() 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

Vídeos