I want to make a Tab Layout with ViewPager2. I have already a working solution with ViewPager, but I have to change it to ViewPager2, because of some issue. I found some example, but these writed in Java, but I working with C#. I asking for help with following things:
write a suitable adapter for ViewPager2, adding fragments to it, reach the new methods of it.
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.viewpager.widget.ViewPager
android:id="@+id/pager"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
</RelativeLayout>
MainActivity OnCreate:
pager = FindViewById<ViewPager2>(Resource.Id.pager);
PagerAdapter adapter = new PagerAdapter(this);
adapter.AddFragment(new FragmentA());
adapter.AddFragment(new FragmentB());
adapter.AddFragment(new FragmentC());
pager.Adapter = adapter;
adapter.NotifyDataSetChanged();
Adapter:
public class PagerAdapter : FragmentPagerAdapter
public List<AndroidX.Fragment.App.Fragment> fragments = new List<AndroidX.Fragment.App.Fragment>();
public List<string> fragmentTitles = new List<string>();
public PagerAdapter(AndroidX.Fragment.App.FragmentManager fm) : base(fm)
public void AddFragment(AndroidX.Fragment.App.Fragment fragment, string title)
fragments.Add(fragment);
fragmentTitles.Add(title);
public override int Count => fragments.Count;
public override AndroidX.Fragment.App.Fragment GetItem(int position)
return fragments[position];
public override ICharSequence GetPageTitleFormatted(int position)
return new Java.Lang.String(fragmentTitles[position]);
FragmentA:
public class FragmentA : AndroidX.Fragment.App.Fragment
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
return inflater.Inflate(Resource.Layout.fragment_a_layout, container, false);
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
@Marcell Zólyomi
You need to start your migration with a FragmentStateAdapter. Example below
public class MonitorsViewPagerFragmentAdapter : FragmentStateAdapter
private readonly int itemCount;
//Refer to https://stackoverflow.com/questions/61779776/leak-canary-detects-memory-leaks-for-tablayout-with-viewpager2/62184494#62184494
public MonitorsViewPagerFragmentAdapter(FragmentManager fragmentManager, Lifecycle lifecylce, int itemCount) : base(fragmentManager, lifecylce)
this.itemCount = itemCount;
// implement inherited abstract member ItemCount
public override int ItemCount => itemCount;
// implement inherited abstract member - CreateFragment of Viewpager2 replaces GetItem of ViewPager. Creating a new instance each time instead of reusing instances as was done in ViewPager
public override Fragment CreateFragment(int position)
return position switch
0 => MonitorFragment.NewInstance(),
1 => ContinuousMonitoringFragment.NewInstance(),
2 => NonContinuousMonitoringFragment.NewInstance(),
_ => null,
Then in your parent fragment in your OnViewCreated you would instantiate the FragmentStateAdapter like the following lines
// FragmentStateAdapter - which calls CreateFragment for the three fragments - note the extra param ViewLifecycleOwner.Lifecycle
// Refer to https://stackoverflow.com/questions/61779776/leak-canary-detects-memory-leaks-for-tablayout-with-viewpager2/62184494#62184494
// This is using the third of the three FragmentStateAdapter public constructors.
// Note - it is also an abstract class, so we can add out own params. e.g. passing the total number of fragments that the ViewPager2 will hold.
monitorsViewPagerFragmentAdapter = new MonitorsViewPagerFragmentAdapter(ChildFragmentManager, ViewLifecycleOwner.Lifecycle, 3);
Then for your viewPager2
// Create a new ViewPager2.OnPageChangeCallback and then register with the ViewPager2 - must be unregistered in OnDestroy
monitorsViewPagerOnPageChangeCallback = new OnPageChangeCallback(Activity);
monitorsViewPager.RegisterOnPageChangeCallback(monitorsViewPagerOnPageChangeCallback);
monitorsViewPager.Orientation = ViewPager2.OrientationHorizontal;
// We need all three fragments in memory, setting OffscreenPageLimit=2 will achieve that
monitorsViewPager.OffscreenPageLimit = 2; // ViewPager2.OffscreenPageLimitDefault;
monitorsViewPager.Adapter = monitorsViewPagerFragmentAdapter;
Next the tabs
tabLayout.TabMode = TabLayout.ModeFixed;
tabLayout.TabGravity = TabLayout.GravityCenter;
TabLayoutMediator tabMediator = new TabLayoutMediator(tabLayout, monitorsViewPager, new TabConfigurationStrategy(Activity));
tabMediator.Attach();
An optional OnPageChangeCallback
class OnPageChangeCallback : ViewPager2.OnPageChangeCallback
// Don't really need this as we are not using it.
private readonly Context context;
public OnPageChangeCallback(Context context)
this.context = context;
public override void OnPageSelected(int position)
//Log.Debug(logTag, "OnPageSelected - SelectedItem " + selectedItem.ToString());
And a TabConfigurationStrategy
class TabConfigurationStrategy : Java.Lang.Object, TabLayoutMediator.ITabConfigurationStrategy
// using this for the tab titles
private readonly Context context;
public TabConfigurationStrategy(Context context)
this.context = context;
public void OnConfigureTab(TabLayout.Tab tab, int position)
tab.SetText(context.Resources.GetStringArray(Resource.Array.monitor_tab_titles)[position]);
See the following link for more information https://developer.android.com/training/animation/vp2-migration and follow the links in the code for more info.
As I understand it I have to make three separate Fragment.cs file, and one for an adapter and of course I have an activity, but I don't understand which one is my parent fragment, becaouse the ViewPager2 is on my activity, so I thought the parent is my activity not one of my fragment. Could you explain it to me?
@Marcell Zólyomi
If you look at the definition of FragmentStateAdapter you'll see there are 3 constructors. I'm using the 3rd ctor, because I'm calling it from a Fragment I therefore need to use ChildFragmentManager. In your case from an Activity you can use SupportFragmentManager using the same ctor.
I only have a single Activity in my app as I'm using Android's NavigationComponent which means fragments for all screens. Therefore in my case, it has to be the ChildFragmentManager.
The easiest way to set up a FragmentStateAdapter is to create a new class eg. public class TestViewPager2Adapter. Inherit TestViewPager2Adapter from FragmentStateAdapter and then let VS do the work for you.
So now you have red squiggles on FragmentStateAdapter
public class TestViewPagerAdapter : FragmentStateAdapter
Right Click on the squiggly and choose Quick actions and it will suggest adding the using AndroidX.ViewPager2.Adapter - just accept the suggestion.
Next, you'll have another squiggly on TestViewPager2Adapter. Right-click on that squiggly and accept the suggestion implement abstract class. You end up with
public class TestViewPagerAdapter : FragmentStateAdapter
public override int ItemCount => throw new NotImplementedException();
public override AndroidX.Fragment.App.Fragment CreateFragment(int p0)
throw new NotImplementedException();
VS has now written the important parts of the code for you.
@Marcell Zólyomi
I just read Javan's answer. So I thought I should point out the following.
I don't believe his technique of returning an already created fragment is correct. The migration docs specifically say Make sure that your new createFragment() method always supplies a new fragment instance each time the function is called instead of reusing instances.
Hence I'd suggest your CreateFragment should be written the way I showed in my example. In other words, do not use a List<AndroidX.Fragment.App.Fragment> fragments in the FragmentStateAdapter.
@Marcell Zólyomi
I tried your way, but the NewInstance method doesn't apper. You made it yourself?
Yes here is an example of the MonitorFragment
public MonitorFragment() { }
public static MonitorFragment NewInstance()
MonitorFragment fragment = new MonitorFragment();
return fragment;
Android requires a parameterless constructor for a Fragment, which it will automatically use on a configuration change. Hence the use of methods like GetInstance or NewInstance. They then allow you to pass in parameters to the Fragment if required, or you could pass in a Bundle.
Hello @Marcell Zólyomi ,
Welcome to our Microsoft Q&A platform!
To migrate to Viewpager2, there are some important points to note:
To use the ViewPager2
control in Xamarin.Android, we need to install the Xamarin.AndroidX.ViewPager2
nuget. And update/install Xamarin.Google.Android.Material
package to use TabLayoutMediator
, see below.
When ViewPager used FragmentPagerAdapter
to page through a small, fixed number of fragments, use FragmentStateAdapter
with ViewPager2
While TabLayout
uses its own setupWithViewPager()
method to integrate with ViewPager
, it requires a TabLayoutMediator
instance to integrate with ViewPager2
.
##Update:
Thanks to GrahamMcKechnie for the reminded, it's my mistake. I've updated the relevant code.
Here is the sample code, you could refer to:
public class ViewPager2_TestActivity : AppCompatActivity
public static List<string> fragmentTitles;
TabLayout tabLayout;
ViewPager2 pager;
protected override void OnCreate(Bundle savedInstanceState)
base.OnCreate(savedInstanceState);
// Create your application here
SetContentView(Resource.Layout.layout_viewpager2);
tabLayout = FindViewById<TabLayout>(Resource.Id.tabLayout);
pager = FindViewById<ViewPager2>(Resource.Id.pager);
CustomViewPager2Adapter adapter = new CustomViewPager2Adapter(this.SupportFragmentManager, this.Lifecycle);
fragmentTitles = = new List<string>() { "FragmentA", "FragmentB", "FragmentC"};
pager.Adapter = adapter;
adapter.NotifyDataSetChanged();
new TabLayoutMediator(tabLayout, pager, new CustomStrategy()).Attach();
public class CustomViewPager2Adapter : FragmentStateAdapter
public CustomViewPager2Adapter(AndroidX.Fragment.App.FragmentManager fragmentManager, Lifecycle lifecycle) : base(fragmentManager, lifecycle)
public override int ItemCount => 3;
private AndroidX.Fragment.App.Fragment fragment = new AndroidX.Fragment.App.Fragment();
public override AndroidX.Fragment.App.Fragment CreateFragment(int position)
switch (position)
case 0:
fragment = new ViewPage2FragmentA();
break;
case 1:
fragment = new ViewPage2FragmentB();
break;
case 2:
fragment = new ViewPage2FragmentC();
break;
return fragment;
public class ViewPage2FragmentA : AndroidX.Fragment.App.Fragment
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
return inflater.Inflate(Resource.Layout.fragment_a_layout, container, false);
public class CustomStrategy : Java.Lang.Object, ITabConfigurationStrategy
public void OnConfigureTab(TabLayout.Tab p0, int p1)
p0.SetText(ViewPager2_TestActivity.fragmentTitles[p1]);
Check the doc: https://developer.android.com/training/animation/vp2-migration#migrate
Best Regards,
Jarvan Zhang
If the response is helpful, please click "Accept Answer" and upvote it.
Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.