I came to know about ViewPager2 and tried to implement it, but didn't find any proper example.
Can anyone tell me how can I use it.
I am looking for proper usage, not an example.
I came to know about ViewPager2 and tried to implement it, but didn't find any proper example.
Can anyone tell me how can I use it.
I am looking for proper usage, not an example.
 
    
     
    
    Check : Migrate from ViewPager to ViewPager2
Check : Create swipe views with tabs using ViewPager2
Check out my answer if you want to implement Carousel using View Pager2
How to use TabLayout with ViewPager2
SAMPLE CODE
Use below dependencies
implementation 'com.google.android.material:material:1.1.0-alpha08'
implementation 'androidx.viewpager2:viewpager2:1.0.0-beta02'
SAMPLE CODE
XMl layout
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    <com.google.android.material.appbar.AppBarLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
        <androidx.appcompat.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                android:background="?attr/colorPrimary"
                app:layout_scrollFlags="scroll|enterAlways"
                app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>
        <com.google.android.material.tabs.TabLayout
                android:id="@+id/tabs"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"/>
    </com.google.android.material.appbar.AppBarLayout>
    <androidx.viewpager2.widget.ViewPager2
            android:id="@+id/viewpager"
            app:layout_anchor="@id/tabs"
            app:layout_anchorGravity="bottom"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
    />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
Activity
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import kotlinx.android.synthetic.main.activity_main.*
import com.google.android.material.tabs.TabLayoutMediator
import com.google.android.material.tabs.TabLayout
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
//        setSupportActionBar(toolbar)
        viewpager.adapter = AppViewPagerAdapter(supportFragmentManager, lifecycle)
        TabLayoutMediator(tabs, viewpager, object : TabLayoutMediator.OnConfigureTabCallback {
            override fun onConfigureTab(tab: TabLayout.Tab, position: Int) {
                // Styling each tab here
                tab.text = "Tab $position"
            }
        }).attach()
    }
}
OUTPUT
From Docs
New features
API changes
FragmentStateAdapter replaces FragmentStatePagerAdapterRecyclerView.Adapter replaces PagerAdapterregisterOnPageChangeCallback replaces addPageChangeListenerSAMPLE CODE
add the latest
dependenciesforViewPager2
implementation 'androidx.viewpager2:viewpager2:1.0.0-alpha01'
layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">
    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/view_pager"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>
activity
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.viewpager2.widget.ViewPager2;
import java.util.ArrayList;
public class MyActivity extends AppCompatActivity {
    ViewPager2 myViewPager2;
    MyAdapter MyAdapter;
    private ArrayList<String> arrayList = new ArrayList<>();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my);
        myViewPager2 = findViewById(R.id.view_pager);
        arrayList.add("Item 1");
        arrayList.add("Item 2");
        arrayList.add("Item 3");
        arrayList.add("Item 4");
        arrayList.add("Item 5");
        MyAdapter = new MyAdapter(this, arrayList);
        myViewPager2.setOrientation(ViewPager2.ORIENTATION_VERTICAL);
        myViewPager2.setAdapter(MyAdapter);
    }
}
MyAdapter
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
    private Context context;
    private ArrayList<String> arrayList = new ArrayList<>();
    public MyAdapter(Context context, ArrayList<String> arrayList) {
        this.context = context;
        this.arrayList = arrayList;
    }
    @NonNull
    @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(context).inflate(R.layout.list_item, parent, false);
        return new MyViewHolder(view);
    }
    @Override
    public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
        holder.tvName.setText(arrayList.get(position));
    }
    @Override
    public int getItemCount() {
        return arrayList.size();
    }
    public class MyViewHolder extends RecyclerView.ViewHolder {
        TextView tvName;
        public MyViewHolder(@NonNull View itemView) {
            super(itemView);
            tvName = itemView.findViewById(R.id.tvName);
        }
    }
}
now we need to use
ViewPager2.OnPageChangeCallback()to get Swipe event ofViewPager2
SAMPLE CODE
    myViewPager2.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
            super.onPageScrolled(position, positionOffset, positionOffsetPixels);
        }
        @Override
        public void onPageSelected(int position) {
            super.onPageSelected(position);
            Log.e("Selected_Page", String.valueOf(position));
        }
        @Override
        public void onPageScrollStateChanged(int state) {
            super.onPageScrollStateChanged(state);
        }
    });
we can set Orientation using
myViewPager2.setOrientation()
SAMPLE CODE
For HORIZONTAL Orientation use 
myViewPager2.setOrientation(ViewPager2.ORIENTATION_HORIZONTAL);
For VERTICAL Orientation use 
myViewPager2.setOrientation(ViewPager2.ORIENTATION_VERTICAL);
We can use
notifyDataSetChangedsame as we are using inRecyclerView.Adapter
SAMPLE CODE to add new item
    btnAdd.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            arrayList.add("New ITEM ADDED");
            MyAdapter.notifyDataSetChanged();
        }
    });
SAMPLE CODE to remove new item
    btnRemove.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            arrayList.remove(3);
            MyAdapter.notifyItemRemoved(3);
        }
    });
Fragment with ViewPager2First create a
ViewPagerFragmentAdapterclass which extendsFragmentStateAdapter
import java.util.ArrayList;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.viewpager2.adapter.FragmentStateAdapter;
public class ViewPagerFragmentAdapter extends FragmentStateAdapter {
    private ArrayList<Fragment> arrayList = new ArrayList<>();
    public ViewPagerFragmentAdapter(@NonNull FragmentManager fragmentManager) {
        super(fragmentManager);
    }
    @NonNull
    @Override
    public Fragment getItem(int position) {
        return arrayList.get(position);
    }
    public void addFragment(Fragment fragment) {
        arrayList.add(fragment);
    }
    @Override
    public int getItemCount() {
        return arrayList.size();
    }
}
Now use like this in your activity
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.viewpager2.widget.ViewPager2;
import neel.com.bottomappbar.R;
public class MainActivity extends AppCompatActivity {
    ViewPager2 myViewPager2;
    ViewPagerFragmentAdapter myAdapter;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        myViewPager2 = findViewById(R.id.view_pager);
        myAdapter = new ViewPagerFragmentAdapter(getSupportFragmentManager());
        // add Fragments in your ViewPagerFragmentAdapter class
        myAdapter.addFragment(new FragmentOne());
        myAdapter.addFragment(new Fragmenttwo());
        myAdapter.addFragment(new FragmentThree());
        // set Orientation in your ViewPager2
        myViewPager2.setOrientation(ViewPager2.ORIENTATION_VERTICAL);
        myViewPager2.setAdapter(myAdapter);
    }
}
for more information check this
New features
setUserInputEnabled, isUserInputEnabled)API changes
ViewPager2 class finalBug fixes
FragmentStateAdapter stability fixesSAMPLE CODE to disable swiping in viewpager2
myViewPager2.setUserInputEnabled(false);// SAMPLE CODE to disable swiping in viewpager2
myViewPager2.setUserInputEnabled(true);//SAMPLE CODE to enable swiping in viewpager2
New features
API changes
FragmentStateAdapter now requires a Lifecycle object. Two utility constructors added to obtain it from the host FragmentActivity or the host FragmentSAMPLE CODE
ViewPagerFragmentAdapter
import java.util.ArrayList;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.lifecycle.Lifecycle;
import androidx.viewpager2.adapter.FragmentStateAdapter;
public class ViewPagerFragmentAdapter extends FragmentStateAdapter {
    private ArrayList<Fragment> arrayList = new ArrayList<>();
    public ViewPagerFragmentAdapter(@NonNull FragmentManager fragmentManager, @NonNull Lifecycle lifecycle) {
        super(fragmentManager, lifecycle);
    }
    @NonNull
    @Override
    public Fragment getItem(int position) {
        return arrayList.get(position);
    }
    public void addFragment(Fragment fragment) {
        arrayList.add(fragment);
    }
    @Override
    public int getItemCount() {
        return arrayList.size();
    }
}
MainActivity code
import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.viewpager2.widget.ViewPager2;
import neel.com.bottomappbar.R;
public class MainActivity extends AppCompatActivity {
    ViewPager2 myViewPager2;
    ViewPagerFragmentAdapter myAdapter;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        myViewPager2=findViewById(R.id.view_pager);
        myAdapter = new ViewPagerFragmentAdapter(getSupportFragmentManager(), getLifecycle());
        // add Fragments in your ViewPagerFragmentAdapter class
        myAdapter.addFragment(new FragmentOne());
        myAdapter.addFragment(new Fragmenttwo());
        myAdapter.addFragment(new FragmentThree());
        myViewPager2.setOrientation(ViewPager2.ORIENTATION_VERTICAL);
        myViewPager2.setAdapter(myAdapter);
    }
}
Version 1.0.0-alpha05New features
ItemDecorator introduced with a behaviour consistent with RecyclerView.MarginPageTransformer introduced to provide an ability to create space between pages (outside of page inset).CompositePageTransformer introduced to provide an ability to combine multiple PageTransformersAPI changes
FragmentStateAdapter#getItem method renamed to FragmentStateAdapter#createFragment - previous method name has proven to be a source of bugs in the past.OFFSCREEN_PAGE_LIMIT_DEFAULT value changed from 0 to -1. No need for a client code change if the OFFSCREEN_PAGE_LIMIT_DEFAULTconstant used.SAMPLE CODE
Activity code
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.RecyclerView;
import androidx.viewpager2.widget.MarginPageTransformer;
import androidx.viewpager2.widget.ViewPager2;
import neel.com.bottomappbar.R;
public class MainActivity extends AppCompatActivity {
    ViewPager2 myViewPager2;
    ViewPagerFragmentAdapter myAdapter;
    private ArrayList<Fragment> arrayList = new ArrayList<>();
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        myViewPager2 = findViewById(R.id.myViewPager2);
        // add Fragments in your ViewPagerFragmentAdapter class
        arrayList.add(new FragmentOne());
        arrayList.add(new Fragmenttwo());
        arrayList.add(new FragmentThree());
        myAdapter = new ViewPagerFragmentAdapter(getSupportFragmentManager(), getLifecycle());
        // set Orientation in your ViewPager2
        myViewPager2.setOrientation(ViewPager2.ORIENTATION_HORIZONTAL);
        myViewPager2.setAdapter(myAdapter);
        myViewPager2.setPageTransformer(new MarginPageTransformer(1500));
    }
}
ViewPagerFragmentAdapter
import java.util.ArrayList;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.lifecycle.Lifecycle;
import androidx.viewpager2.adapter.FragmentStateAdapter;
public class ViewPagerFragmentAdapter extends FragmentStateAdapter {
    private ArrayList<Fragment> arrayList = new ArrayList<>();
    public ViewPagerFragmentAdapter(@NonNull FragmentManager fragmentManager, @NonNull Lifecycle lifecycle) {
        super(fragmentManager, lifecycle);
    }
    @NonNull
    @Override
    public Fragment createFragment(int position) {
        switch (position) {
            case 0:
                return new FragmentOne();
            case 1:
                return new Fragmenttwo();
            case 2:
                return new FragmentThree();
        }
        return null;
    }
    @Override
    public int getItemCount() {
        return 3;
    }
}
 
    
    Actually now there is an official samples repo for ViewPager2 (linked below)
Repo contains following samples (Quoting from the repo readme below)
Samples
- ViewPager2 with Views - shows how to set up a ViewPager2 with Views as pages
- ViewPager2 with Fragments - shows how to set up a ViewPager2 with Fragments as pages
- ViewPager2 with a Mutable Collection (Views) - demonstrates usage of ViewPager2 with Views as pages and mutations in a page adapter
- ViewPager2 with a Mutable Collection (Fragments) - demonstrates usage of ViewPager2 with Fragments as pages, and mutations in a page adapter
- ViewPager2 with a TabLayout (Views) - shows how to set up a ViewPager2 with Views as pages, and link it to a TabLayout
Simple example of ViewPager2 with Fragments in Kotlin
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    tools:context=".MainActivity">
    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/pager2_container"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"/>
</LinearLayout>
MainActivity.kt
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val viewPager2 = findViewById<ViewPager2>(R.id.pager2_container)
        val fragmentList = arrayListOf(
            FirstFragment.newInstance(),
            SecondFragment.newInstance(),
            ThirdFragment.newInstance()
        )
        viewPager2.adapter = ViewPagerAdapter(this, fragmentList)
   }
}
FirstFragment.kt (SecondFragment.kt and ThirdFragment.kt looks similar to FirstFragment.kt)
class FirstFragment : Fragment() {
    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.fragment_first, container, false)
    }
    companion object{
        fun newInstance() = FirstFragment()
    }
}
ViewPagerAdapter.kt
class ViewPagerAdapter(fa:FragmentActivity, private val fragments:ArrayList<Fragment>): FragmentStateAdapter(fa) {
    override fun getItemCount(): Int = fragments.size
    override fun createFragment(position: Int): Fragment = fragments[position]
}
Some other useful resources:
Training: https://developer.android.com/training/animation/screen-slide-2
Release notes: https://developer.android.com/jetpack/androidx/releases/viewpager2
Medium article by a GDE : Exploring the ViewPager2
 
    
     
    
    Use of ViewPager2 in Android
As mentioned on Developer Site
API changes
FragmentStateAdapter replaces FragmentStatePagerAdapter
RecyclerView.Adapter replaces PagerAdapter
registerOnPageChangeCallback replaces addPageChangeListener
In Simple Words they make it View Pager adapter work like Recycle View Adapter.
Note:- We don't need to use fragment in View Pager 2. It is fully depend on RecyclerView.Adapter inflate layout.
Here is sample gitHub repo Link
Example:-
MainActivity.class
public class MainActivity extends AppCompatActivity {
    
    private ViewPager2 mPager;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        getSupportActionBar().setTitle("View Pager 2");
        mPager = findViewById(R.id.pager);
        mPager.setAdapter(new MyViewPagerAdapter(this));
    }
    
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return super.onCreateOptionsMenu(menu);
    }
    
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (R.id.change == item.getItemId()) {
            mPager.setOrientation(mPager.getOrientation() != ViewPager2.ORIENTATION_VERTICAL ? ViewPager2.ORIENTATION_VERTICAL : ViewPager2.ORIENTATION_HORIZONTAL);
        }
        return super.onOptionsItemSelected(item);
    }
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/pager"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</android.support.constraint.ConstraintLayout>
MyViewPagerAdapter.class
public class MyViewPagerAdapter extends RecyclerView.Adapter<MyHolder> {
    
    private Context context;
    
    public MyViewPagerAdapter(Context context) {
        this.context=context;
    }
    
    @NonNull
    @Override
    public MyHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        return new MyHolder(LayoutInflater.from(context).inflate(R.layout.cell_item, parent, false));
    }
    
    @Override
    public void onBindViewHolder(@NonNull MyHolder holder, int position) {
      holder.mText.setText("Page "+(position+1));
    }
    
    @Override
    public int getItemCount() {
        return 10;
    }
}
cell_item.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:id="@+id/text"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:text="Page 1"
        android:textSize="20sp" />
</android.support.constraint.ConstraintLayout>
MyHolder.class
class MyHolder extends RecyclerView.ViewHolder {
    
    public TextView mText;
    
    public MyHolder(@NonNull View itemView) {
        super(itemView);
        mText = itemView.findViewById(R.id.text);
    }
}
output:
Here is what I did to implemet ViewPager2 with TabLayout with 3 Fragment full Examble:
Layout  contains ViewPager2 with TabLayout:
 <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:orientation="vertical"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/include3">
        <com.google.android.material.tabs.TabLayout
            android:id="@+id/tab_layout"
            android:layout_width="match_parent"
            android:background="@color/colorPrimary"
            app:tabTextColor="@color/tab_dismiss_color"
            app:tabSelectedTextColor="@color/green"
            android:layout_height="wrap_content" />
        <View
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:layout_gravity="bottom"
            android:background="#e4e4e4" />
        <androidx.viewpager2.widget.ViewPager2
            android:id="@+id/pager"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1" />
    </LinearLayout>
init ViewPager2 and set Tabs Name:
 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_report);
        ButterKnife.bind(this);
        actionBarTitleId.setText(R.string.reports);
        viewPager.setAdapter(new ViewPagerAdapter(this));
        new TabLayoutMediator(tabLayout, viewPager, (tab, position) -> {
            switch (position) {
                case 0:
                    tab.setText(R.string.financial_duty_str);
                    break;
                case 1:
                    tab.setText(R.string.financial_unpaid_str);
                    break;
                case 2:
                    tab.setText(R.string.financial_paid_str);
                    break;
            }
        }).attach();
    }
ViewPager2 adapter :
public class ViewPagerAdapter extends FragmentStateAdapter {
    public ViewPagerAdapter(@NonNull FragmentActivity fragmentActivity) {
        super(fragmentActivity);
    }
    @NonNull
    @Override
    public Fragment createFragment(int position) {
        switch (position) {
            case 0:
                return new FinancialFragment();
            case 1:
                return new FinancialUnPaidFragment();
            case 2:
                return new FinancialPaidFragment();
            default:
                return null;
        }
    }
    @Override
    public int getItemCount() {
        return 3;
    }
dependency used:
implementation "androidx.viewpager2:viewpager2:1.0.0"
implementation 'com.google.android.material:material:1.1.0-alpha10'
 
    
    How to use it explained very clearly. Let me give small but very crucial tips and details about ViewPager2 especially if it's inside a fragment about how to prevent memory leaks
Don't use the constructor that takes fragment especially if you are using TabLayout.
public FragmentStateAdapter(@NonNull Fragment fragment) {
    this(fragment.getChildFragmentManager(), fragment.getLifecycle());
}
because it has risk of memory leak as described here
instead use the one takes FragmentManager and LifeCycle. And don't send lifeCycle of fragment as argument, use viewLifeCycleOwner's lifecycle because viewLifeCycleOwner represents life cycle of fragment's view.
 class NavigableFragmentStateAdapter(
    fragmentManager: FragmentManager,
    lifecycle: Lifecycle
) : FragmentStateAdapter(fragmentManager, lifecycle) {
}
and set adapter with in onCreateView
viewPager.adapter =
            NavigableFragmentStateAdapter(childFragmentManager, viewLifecycleOwner.lifecycle)
TabLayout when ViewPager2 is inside a fragment do not forget to detach TabLayout and set adapter of ViewPager2 asdetach TabLayoutMediator since it causing memory leaks when it's in a fragment
TabLayoutMediator(tabLayout, viewPager2, tabConfigurationStrategy).detach()     
viewPager2.adapter = null
inside onDestroyView method of Fragment
If you wish to use pages of ViewPager as navHostFragment with navigation components to navigate back to child fragments register FragmentTransactionCallback in FragmentStateAdapter as
private val fragmentTransactionCallback =
    object : FragmentStateAdapter.FragmentTransactionCallback() {
        override fun onFragmentMaxLifecyclePreUpdated(
            fragment: Fragment,
            maxLifecycleState: Lifecycle.State
        ) = if (maxLifecycleState == Lifecycle.State.RESUMED) {
            // This fragment is becoming the active Fragment - set it to
            // the primary navigation fragment in the OnPostEventListener
            OnPostEventListener {
                fragment.parentFragmentManager.commitNow {
                    setPrimaryNavigationFragment(fragment)
                }
            }
        } else {
            super.onFragmentMaxLifecyclePreUpdated(fragment, maxLifecycleState)
        }
    }
init {
    // Add a FragmentTransactionCallback to handle changing
    // the primary navigation fragment
    registerFragmentTransactionCallback(fragmentTransactionCallback)
}
Also if you wish to see some samples how to use ViewPager2 with navigation components, dynamic feature modules and combining with BottomNavigationView you can check out the tutorials in this github repo.
 
    
    Just in case one may want to listen for ViewPager2.OnPageChangeCallback events:
private final ViewPager2.OnPageChangeCallback onPageChangeListener = new ViewPager2.OnPageChangeCallback() {
    /**
     * This method will be invoked when the current page is scrolled, either as part
     * of a programmatically initiated smooth scroll or a user initiated touch scroll.
     * @param position             Position index of the first page currently being displayed.
     *                             Page position+1 will be visible if positionOffset is nonzero.
     * @param positionOffset       Value from [0, 1) indicating the offset from the page at position.
     * @param positionOffsetPixels Value in pixels indicating the offset from position.
     */
    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        super.onPageScrolled(position, positionOffset, positionOffsetPixels);
    }
    /**
     * This method will be invoked when a new page becomes selected.
     * Animation is not necessarily complete.
     * @param position             Position index of the first page currently being displayed.
     *                             Page position+1 will be visible if positionOffset is nonzero.
     */
    @Override
    public void onPageSelected (int position) {
        super.onPageSelected(position);
        if (position == 2) { // SomeFragment
            Log.d(LOG_TAG, "ViewPager2.onPageSelected( " + position + " )");
            SomePagerAdapter adapter = (SomePagerAdapter) viewpager.getAdapter();
            if (adapter != null) {
                SomeFragment fragment = (SomeFragment) adapter.getItem(position);
                fragment.onLateInit();
            }
        }
    }
};
To be applied with ViewPager2.registerOnPageChangeCallback():
viewpager.registerOnPageChangeCallback(this.onPageChangeListener);
The FragmentStateAdapter needs to hold an ArrayList<Fragment> mItems, so that one can access the instances, which are being constructed ahead of time. SomeFragment exposes method public void onLateInit(), because @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) can possibly not be used (depends on the Fragment).
public Fragment getItem(int position) {
    return this.mItems.get(position);
}
Alike this one one work around the issue, what the Fragment is being constructed long before one might be able to properly initialize it's view, eg. with data entered in the previous one Fragment. It might not be the optimum for a large amount of Fragment (...), but for a few it works pretty well.
 
    
    here is kotlin version implementation of @sushildlh answer in Kotlin.
in this code I am implementing viewpager2 with recyclerview to view images.
also i am using viewbinding
food_details.xml
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".presentation.recipeitem.RecipeDetailsFragment">
    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/viewPager2"
        android:layout_width="0dp"
        android:layout_height="300dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:src="@tools:sample/avatars" />
...
the fragment which inflates this xml
@AndroidEntryPoint
class RecipeDetailsFragment : Fragment(R.layout.fragment_recipe_details) {
private val viewModel: RecipeItemViewModel by viewModels()
private val viewBinding: FragmentRecipeDetailsBinding by viewBinding()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    bindRecipeData(//object of data that is to be desplayed)
}
private fun bindRecipeData(recipeDetailedInfo: RecipeDetailedInfo?) {
    recipeDetailedInfo?.let {
        with(viewBinding) {
            viewPager2.adapter = ViewPagerAdapter(it.images)
            viewPager2.setPageTransformer(ZoomOutPageTransformer())
            lifecycleScope.launchWhenCreated {
                delay(500)
                viewPager2.setCurrentItem(if (it.images.size >= 2) 1 else 0, true)
            }
        }
    }
}....
in the fragment i am creating object of the adapter and sending directly list of strings that contains the images URLs
here is the viewpager adapter which is basically a normal recyclerview adapter
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.blogspot.soyamr.recipes2.databinding.ImageviewBinding
import com.squareup.picasso.Picasso
class ViewPagerAdapter(private val images: List<String>) :
    RecyclerView.Adapter<ViewPagerAdapter.ImageViewHolder>() {
    class ImageViewHolder(private val imageViewBinding: ImageviewBinding) :
        RecyclerView.ViewHolder(imageViewBinding.root) {
        fun bind(imageLink: String) {
            Picasso.get().load(imageLink).into(imageViewBinding.root)
        }
        companion object {
            fun from(parent: ViewGroup): ImageViewHolder {
                val itemBinding =
                    ImageviewBinding.inflate(LayoutInflater.from(parent.context), parent, false)
                return ImageViewHolder(itemBinding)
            }
        }
    }
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ImageViewHolder {
        return ImageViewHolder.from(parent)
    }
    override fun onBindViewHolder(holder: ImageViewHolder, position: Int) {
        holder.bind(images[position])
    }
    override fun getItemCount(): Int = images.size
}
in the recyclerview i am inflating this imageview.xml
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.imageview.ShapeableImageView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent" android:layout_height="match_parent"
    android:scaleType="centerCrop"
    android:theme="@style/roundedImageView"
    />
you use your complex xml view if needed
 
    
    Simple example with two differente fragments, usin tabs. Main layout:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/mainConstraintLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/mainViewPager"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/mainTabLayout">
    </androidx.viewpager2.widget.ViewPager2>
    <com.google.android.material.tabs.TabLayout
        android:id="@+id/mainTabLayout"
        android:layout_width="match_parent"
        android:layout_height="@dimen/toolbar_height"
        android:background="@color/brown_normal"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:tabIndicatorColor="@color/yellow_light"
        app:tabIndicatorHeight="3dp"
        app:tabSelectedTextColor="@color/yellow_light"
        app:tabTextColor="@color/yellow_normal"
        tools:ignore="SpeakableTextPresentCheck" />
</androidx.constraintlayout.widget.ConstraintLayout>
Adapter:
public class MainToolsAdapter extends FragmentStateAdapter
{
    // The quantity of tab is fixed
    private static final int FRAGMENT_COUNT = 2;
    // Titles for each tab    
    private final String[] titles = new String[FRAGMENT_COUNT];
    public MainToolsAdapter(@NonNull FragmentManager fragmentManager, @NonNull Lifecycle lifecycle, Context context)
    {
        super(fragmentManager, lifecycle);
        // Load titles for tab from resourses
        titles[0] = context.getResources().getString(R.string.tab_1);
        titles[1] = context.getResources().getString(R.string.tab_2);
    }
    @NonNull
    @Override
    public Fragment createFragment(int position)
    {
        // Create fragments according to position
        if(position == 0)
        {
            return new FragmentTabOne();
        }
        return new FragmentTabTwo();
    }
    @Override
    public int getItemCount()
    {
        return FRAGMENT_COUNT;
    }
    public String getItemTitle(int position)
    {
        if(position == 0)
        {
            return titles[0];
        }
        return titles[1];
    }
}
Main activity OnCreate:
@Override
protected void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    // Create adapter for ViewPager
    mainToolsAdapter = new MainToolsAdapter(getSupportFragmentManager(), getLifecycle(), this);
    // Set adapter to the ViewPager
    viewPager = findViewById(R.id.mainViewPager);
    viewPager.setAdapter(mainToolsAdapter);
    tabLayout = findViewById(R.id.mainTabLayout);
    // Create the TabLayoutMediator to asociate ViewPager2 to TabLayout
    TabLayoutMediator tabLayoutMediator = new TabLayoutMediator(tabLayout, viewPager, true, new TabLayoutMediator.TabConfigurationStrategy()
    {
        @Override
        public void onConfigureTab(@NonNull TabLayout.Tab tab, int position)
        {
            // When a tab is created this is called, then we can set tab properties, in this case the text
            tab.setText(mainToolsAdapter.getItemTitle(position));
        }
    });
    // After configure we need to realice attach then Tab and ViewPager2 are asociated
    tabLayoutMediator.attach();
}
gradle:
plugins {
    id 'com.android.application'
}
android {
    compileSdk 30
    defaultConfig {
        applicationId "com.xxxx.yyyy"
        minSdk 19
        targetSdk 30
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}
dependencies
{
    implementation fileTree(include: ['*.jar', '*.aar'], dir: 'libs')
    implementation 'androidx.appcompat:appcompat:1.3.1'
    implementation 'com.google.android.material:material:1.4.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.1.1'
    testImplementation 'junit:junit:4.13.2'
    androidTestImplementation 'androidx.test.ext:junit:1.1.3'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}
 
    
    Here my solution (Android Studio 3.6):
In app/build.gradle:
dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation('com.crashlytics.sdk.android:crashlytics:2.10.1@aar') { transitive = true; }
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    implementation 'com.google.android.material:material:1.1.0-beta01'
    implementation 'org.altbeacon:android-beacon-library:2.16.3'
    implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.0.0'
    implementation 'androidx.viewpager2:viewpager2:1.0.0-beta05'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
    implementation "androidx.core:core-ktx:+"
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
}
Here my activity:
import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.viewpager2.widget.ViewPager2;
import java.util.ArrayList;
import java.util.List;
import com.myproject.android.R;
import com.myproject.android.adapter.CustomFragmentStateAdapter;
import com.myproject.android.ui.fragment.BluetoothPageFragment;
import com.myproject.android.ui.fragment.QrPageFragment;
public class QRBluetoothSwipeActivity extends AppCompatActivity {
    private ViewPager2 myViewPager2;
    private CustomFragmentStateAdapter myAdapter;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        // Make sure this is before calling super.onCreate
        setTheme(R.style.AppTheme); // show splash screen
        super.onCreate(savedInstanceState);
        setContentView(R.layout.qr_bluetooth_swipe_activity);
        init();
    }
    private void init() {
        List<Fragment> fragmentList = new ArrayList<Fragment>();
        QrPageFragment m1 = new QrPageFragment();
        BluetoothPageFragment m2 = new BluetoothPageFragment();
        myViewPager2 = findViewById(R.id.viewPager2);
        fragmentList.add(m2);
        fragmentList.add(m1);
        myAdapter = new CustomFragmentStateAdapter(this, fragmentList);
        myViewPager2.setAdapter(myAdapter);
    }
}
Here layout:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ui.actviity.SplashDelayActivity">
    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/viewPager2"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Here my CustomFragmentStateAdapter
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
public class CustomFragmentStateAdapter extends FragmentStateAdapter {
    private List<Fragment> listFragment = new ArrayList<>();
    public CustomFragmentStateAdapter(FragmentActivity fa, List<Fragment> list) {
        super(fa);
        listFragment = list;
    }
    @NotNull
    @Override
    public Fragment createFragment(int position) {
        return listFragment.get(position);
    }
    @Override
    public int getItemCount() {
        return 2;
    }
}
And here my fragments:
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import com.myproject.android.R;
public class BluetoothPageFragment extends Fragment {
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.bluetooth_page_fragment, container, false);
    }
}
and second fragment:
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import com.myproject.android.R;
public class QrPageFragment extends Fragment {
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.qr_page_fragment, container, false);
    }
}
And as result now I use androidx.viewpager2.widget.ViewPager2 with my custom fragments.
And it's work!!!
Nice.
P.S. Another implement:
public class CustomFragmentStateAdapter extends FragmentStateAdapter {
    private ArrayList<Fragment> arrayList = new ArrayList<>();
    public CustomFragmentStateAdapter (FragmentActivity fa) {
        super(fa);
    }
    public void addFragment(Fragment fragment) {
        arrayList.add(fragment);
    }
    @Override
    public int getItemCount() {
        return arrayList.size();
    }
    @NonNull
    @Override
    public Fragment createFragment(int position) {
        // return your fragment that corresponds to this 'position'
        return arrayList.get(position);
    }
}
And use like this (in activity):
 myViewPager2 = findViewById(R.id.viewPager2);
        myAdapter = new CustomFragmentStateAdapter (this);
        myAdapter.addFragment(new QrPageFragment());
        myAdapter.addFragment(new BluetoothPageFragment());
        myViewPager2.setAdapter(myAdapter);
 
    
    I first created a view pager, then migrated to view pager 2 using the instructions given in: https://developer.android.com/training/animation/vp2-migration
 
    
    This is the correct implementation!
typealias FragmentBuilder = () -> Fragment
class MyAdapter(
    fragmentManager: FragmentManager, 
    lifecycle: Lifecycle
) : FragmentStateAdapter(fragmentManager, lifecycle) {
    private val fragmentBuilders = mutableListOf<FragmentBuilder>()
    fun add(fragmentBuilder: FragmentBuilder) {
        fragmentBuilders.add(fragmentBuilder)
    }
    /**
     * Dynamic replacement of fragments
     */
    fun set(position: Int, fragmentBuilder: FragmentBuilder) {
        fragmentBuilders[position] = fragmentBuilder
    }
    override fun getItemCount() = fragmentBuilders.size
    override fun createFragment(position: Int) = fragmentBuilders[position].invoke()
}
Don't even thank)
 
    
    In Kotlin FragmentStateAdapter with ViewPager2 The primary reason to migrate is that ViewPager2 is receiving active development support and ViewPager is not. However, ViewPager2 also offers several other specific advantages. FragmentStateAdapter in ViewPager2 is a little bit different than in ViewPager as follows: 1] Instead of implementing getCount(), implement getItemCount() 2] Instead of implementing getItem(int position), implement createFragment(int position) 3] Constructor signature is different by adding Lifecycle argument which should be included in super as well So replace your ViewPagerFragmentAdapter with below
Kotlin PagerAdapter
class SurveyPagerAdapter(
private val fragmentList: MutableList< Fragment>,
fragment: FragmentManager,
lifecycle: Lifecycle) : FragmentStateAdapter(fragment,lifecycle){
override fun getItemCount(): Int = fragmentList.size
override fun createFragment(position: Int): Fragment {
    return fragmentList[position]
}
fun getFragmentName(position: Int) = fragmentList[position]
fun addFragment(fragment: Fragment) {
    fragmentList.add(fragment)
    notifyDataSetChanged()
}}
Kotlin Activity *Just put on method in onCreate() *
private fun setUpViewPager(){
    val fragmentList : MutableList< Fragment> = mutableListOf()
    fragmentList.add(SurveyPageOneFragment.newInstance(true))
    fragmentList.add(SurveyPageTwoFragment.newInstance(true))
    fragmentList.add(SurveyPageThreeFragment.newInstance(true))
    fragmentList.add(SurveyPageFourFragment.newInstance(true))
    fragmentList.add(SurveyPageFiveFragment.newInstance(true))
    surveyPagerAdapter = SurveyPagerAdapter(fragmentList,supportFragmentManager,lifecycle)
    binding.viewPager.adapter = surveyPagerAdapter
    binding.dotsIndicator.attachTo(binding.viewPager)
}
Kotlin Fragment
class SurveyPageOneFragment : Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    arguments?.let {
    }
}
override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    return inflater.inflate(R.layout.fragment_survey_page_one, container, false)
}
companion object {
    @JvmStatic
    fun newInstance(isMyBoolean: Boolean) = SurveyPageOneFragment().apply {
        val fragment = SurveyPageOneFragment()
        arguments = Bundle().apply {
            putBoolean("REPLACE WITH A STRING CONSTANT", isMyBoolean)
        }
        fragment.arguments
        return fragment
    }
}}
xml code in viewPager2
<androidx.viewpager2.widget.ViewPager2
                android:id="@+id/view_pager"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layoutDirection="ltr"/>
Dot indicator
lib//kotlin dot indicator implementation 'com.tbuonomo:dotsindicator:4.3'
<com.tbuonomo.viewpagerdotsindicator.DotsIndicator
                android:id="@+id/dots_indicator"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                app:dotsColor="@color/colorSurveyEditGreenLight"
                app:dotsCornerRadius="8dp"
                app:dotsSize="16dp"
                app:dotsSpacing="4dp"
                app:dotsWidthFactor="2.5"
                app:selectedDotColor="@color/white"
                app:progressMode="true"
                />
 
    
    I personally used ViewPager2 inside of a Fragment. This is how I do it. Example code on GitHub [https://github.com/codebyjames/Example-Using-ViewPager2-Slide-Page-Adapter]
First in onCreate
        // pager adapter
        val pagerAdapter = ScreenSlidePageAdapter(this@ManagerFragment)
        viewPager.adapter = pagerAdapter
        viewPager.setPageTransformer(ZoomOutPageTransformer())
Adapter for the ViewPager
class ScreenSlidePageAdapter(val fragment: Fragment): FragmentStateAdapter(fragment) {
val fragments = listOf(WalkThroughFragment(), PermissionsFragment(), DatastoreFragment())
override fun getItemCount(): Int {
    return fragments.size
}
override fun createFragment(position: Int): Fragment {
    return fragments[position]
}
}
Transformation for ViewPager2 - optional
class ZoomOutPageTransformer : ViewPager2.PageTransformer {
override fun transformPage(view: View, position: Float) {
    view.apply {
        val pageWidth = width
        val pageHeight = height
        when {
            position < -1 -> { // [-Infinity,-1)
                // This page is way off-screen to the left.
                alpha = 0f
            }
            position <= 1 -> { // [-1,1]
                // Modify the default slide transition to shrink the page as well
                val scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position))
                val vertMargin = pageHeight * (1 - scaleFactor) / 2
                val horzMargin = pageWidth * (1 - scaleFactor) / 2
                translationX = if (position < 0) {
                    horzMargin - vertMargin / 2
                } else {
                    horzMargin + vertMargin / 2
                }
                // Scale the page down (between MIN_SCALE and 1)
                scaleX = scaleFactor
                scaleY = scaleFactor
                // Fade the page relative to its size.
                alpha = (MIN_ALPHA +
                        (((scaleFactor - MIN_SCALE) / (1 - MIN_SCALE)) * (1 - MIN_ALPHA)))
            }
            else -> { // (1,+Infinity]
                // This page is way off-screen to the right.
                alpha = 0f
            }
        }
    }
}
}
My ManagerFragment layout (which contains the ViewPager2)
<androidx.viewpager2.widget.ViewPager2
    android:id="@+id/viewPager"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
