DEV Community

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

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

1 1

How to create a tabbed dialog in .NET for Android or Xamarin.Android

Every once in a while, we need to fulfill certain requirements. Recently, I had to implement a tabbed dialog in .NET for Android or 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

Image of Datadog

The Future of AI, LLMs, and Observability on Google Cloud

Datadog sat down with Google’s Director of AI to discuss the current and future states of AI, ML, and LLMs on Google Cloud. Discover 7 key insights for technical leaders, covering everything from upskilling teams to observability best practices

Learn More

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more