DEV Community

Cover image for How to create a tabbed dialog in Xamarin.Android
Federico Navarrete
Federico Navarrete

Posted on • Updated on • Originally published at supernovaic.blogspot.com

How to create a tabbed dialog in Xamarin.Android

Every once in a while, we need to fulfill certain requirements. Recently, I had to implement a tabbed dialog in Xamarin.Android. Previously, this was relatively easy using a TabHost (RIP), but now, you must use a TabLayout and a ViewPager2, which at first glance sounds like an easy deal, but it became quite complex.

Now, the steps to creating one are the following ones:

Step 1.

Create an XML for the main dialog container (main_tabbed_dialog.xml) with the TabLayout, the ViewPager2, a TextView for the title, and a LinearLayout for the buttons.

<?xml version="1.0" encoding="UTF-8" ?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        android:layout_height="wrap_content"
        android:layout_width="match_parent"
        android:text="Title"
        style="@android:style/TextAppearance.DialogWindowTitle"
        android:textStyle="bold"
        android:paddingTop="?attr/dialogPreferredPadding"
        android:paddingLeft="?attr/dialogPreferredPadding"
        android:paddingRight="?attr/dialogPreferredPadding"></TextView>

    <com.google.android.material.tabs.TabLayout
        android:id="@id/tabLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <androidx.viewpager2.widget.ViewPager2
        android:id="@id/masterViewPager"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <Button
            android:id="@id/btnOK"
            android:layout_width="wrap_content"
            android:padding="5dp"
            android:text="OK"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:layout_centerInParent="true"
            style="@style/Widget.AppCompat.Button.Borderless.Colored" />
    </RelativeLayout>
</LinearLayout>
Enter fullscreen mode Exit fullscreen mode

Note:
The buttons and the title are here because there is a conflict if you add them programmatically. They are not displayed.

Step 2.

Create your views with some XML like these ones:

view1.xml

<?xml version="1.0" encoding="UTF-8" ?>
<ScrollView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:background="@color/white"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fillViewport="true">
    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:paddingLeft="10dp"
        android:paddingRight="10dp">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="view1"
            android:layout_marginBottom="10dp"
            android:textSize="16dp"
            android:layout_marginTop="10dp" />
    </LinearLayout>
</ScrollView>
Enter fullscreen mode Exit fullscreen mode

view2.xml

<?xml version="1.0" encoding="UTF-8" ?>
<ScrollView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:background="@color/white"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fillViewport="true">
    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:paddingLeft="10dp"
        android:paddingRight="10dp">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="view2"
            android:layout_marginBottom="10dp"
            android:textSize="16dp"
            android:layout_marginTop="10dp" />
    </LinearLayout>
</ScrollView>
Enter fullscreen mode Exit fullscreen mode

Step 3.

Create your DialogFragment class:

public partial class MainDialogFragment : DialogFragment
{
    static Context mContext;

    public static MainDialogFragment NewInstance(Context context)
    {
        mContext = context;
        return new MainDialogFragment();
    }

    public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        var view = inflater.Inflate(Resource.Layout.main_tabbed_dialog, container, false);

        var btnOK = view.FindViewById<Button>(Resource.Id.btnOK);

        btnOK.Click = BtnOK_Click;

        return view;
    }

    private void BtnOK_Click(object sender, EventArgs e)
    {
        Dismiss();
    }

    public override void OnViewCreated(View view, Bundle savedInstanceState)
    {
        base.OnViewCreated(view, savedInstanceState);

        ViewPager2 viewPager2 = view.FindViewById<ViewPager2>(Resource.Id.masterViewPager);

        TabLayout tabLayout = view.FindViewById<TabLayout>(Resource.Id.tabLayout);

        var adapter = new MainDialogAdapter(ChildFragmentManager, ViewLifecycleOwner.Lifecycle, 2);

        viewPager2.Adapter = adapter;

        tabLayout.TabMode = TabLayout.ModeFixed;
        tabLayout.TabGravity = TabLayout.GravityCenter;

        TabLayoutMediator tabMediator = new(tabLayout, viewPager2, new TabFullFilterConfigurationStrategy(Activity));
        tabMediator.Attach();
    }
}

//In this class, in the method OnConfigureTab, you change the Tab Titles based on its location
public class TabFullFilterConfigurationStrategy : Java.Lang.Object, TabLayoutMediator.ITabConfigurationStrategy
{
    private readonly Context context;

    public TabFullFilterConfigurationStrategy(Context context)
    {
        this.context = context;
    }

    public void OnConfigureTab(TabLayout.Tab tab, int position)
    {
        tab.SetText(position == 0 ? "View 2" : "View 1");
    }
}

public class MainDialogAdapter : FragmentStateAdapter
{
    public MainDialogAdapter(FragmentManager fragmentManager, Lifecycle lifecylce, int itemCount) : base(fragmentManager, lifecylce)
    {
        this.itemCount = itemCount;
    }

    private readonly int itemCount;
    public override int ItemCount => itemCount;

    public FragmentActivity Fragment { get; }

    public override Fragment CreateFragment(int position)
    {
        return position switch
        {
            0 => View1Fragment.NewInstance(),
            _ => View2Fragment.NewInstance()
        };
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 4.

Create your view classes:

public class View1 : Fragment
{
    public static View1 NewInstance()
    {
        return new View1 { Arguments = new Bundle() };
    }

    public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        base.OnCreateView(inflater, container, savedInstanceState);

        var view = inflater.Inflate(Resource.Layout.view1, container, false);

        return view;
    }
}
Enter fullscreen mode Exit fullscreen mode
public class View2 : Fragment
{
    public static View2 NewInstance()
    {
        return new View2 { Arguments = new Bundle() };
    }

    public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        base.OnCreateView(inflater, container, savedInstanceState);

        var view = inflater.Inflate(Resource.Layout.view2, container, false);

        return view;
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 5.

Show your dialog:

var fm = SupportFragmentManager;
var dialog = MainDialogFragment.NewInstance(this);
dialog.Show(fm, "dialog");
Enter fullscreen mode Exit fullscreen mode

And that's all.

This is an example of a fully functional case:

preview

You can see the fully functional app with the dialogs here:

https://play.google.com/store/apps/details?id=tk.supernova.tipsal

Note:
If you need to share data between the fragments and the main activity, you can follow this tutorial:
https://stackoverflow.com/questions/16036572/how-to-pass-values-between-fragments

Follow me on:

Personal LinkedIn YouTube Instagram Cyber Prophets Sharing Your Stories
Personal LinkedIn YouTube Instagram RedCircle Podcast RedCircle Podcast

sponsor me

Top comments (0)