Creating a custom AlertDialog in Xamarin Android

In most cases the default AlertDialog is good enough for your needs. You can even pass in a collection of items and event handlers. However, there are times where you'd like more control over the customisation of the dialog. Here you've got two choices:

1. Use dialog fragments

2. Pass in a custom view into the AlertDialog - this is what the blog post is about

 

Define your Dialog.axml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:local="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:baselineAligned="true">
            <TextView
                android:id="@+id/text1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textStyle="bold" />
            <TextView
                android:id="@+id/text2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"/>
        </LinearLayout>
</LinearLayout>

 

Define your row template axml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <LinearLayout
        android:id="@+id/title_layout"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <TextView
            android:id="@+id/dialogtitle"
            android:paddingLeft="16dp"
            android:paddingTop="16dp"
            android:paddingBottom="2dp"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Title" />
        <TextView
            android:id="@+id/dialogsubtitle"
            android:paddingLeft="16dp"
            android:paddingTop="2dp"
            android:paddingBottom="8dp"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Subtitle" />
    </LinearLayout>
    <LinearLayout
        android:id="@+id/select_dialog_listview_layout"
        android:paddingBottom="32dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <ListView
            android:id="@+id/select_dialog_listview"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </LinearLayout>
</LinearLayout>

 

Create a method to launch your dialog

public Task<int> ShowCustomDialogAsync(string title, string subtitle, MyTestViewModel[] options)

        {

            var taskCompletionSource = new TaskCompletionSource<int>();

            var activity = Mvx.Resolve<IMvxAndroidCurrentTopActivity> ().Activity;

            var dialogBuilder = new AlertDialog.Builder(activity);

            LayoutInflater inflater = activity.LayoutInflater;

            View view = inflater.Inflate(Resource.Layout.AcceptOrderDialog, null);

            dialogBuilder.SetView(view);

            var dialogTitle = (TextView)view.FindViewById(Resource.Id.dialogtitle);

            dialogTitle.Text = title;

            var dialogSubtitle = (TextView)view.FindViewById(Resource.Id.dialogsubtitle);

            if (!string.IsNullOrEmpty(subtitle))

            {

                dialogSubtitle.Text = subtitle;

                dialogSubtitle.Visibility = ViewStates.Visible;

            }

            else

            {

                dialogSubtitle.Visibility = ViewStates.Gone;

            }

            var dialog = dialogBuilder.Create();

            var primaryList = (ListView)view.FindViewById(Resource.Id.select_dialog_listview);

            primaryList.Adapter = new AcceptTimeOptionViewModelAdapter(dialogBuilder.Context, Resource.Layout.Dialog, options);

            primaryList.Divider = null;

            primaryList.DividerHeight = 0;

            primaryList.ItemClick += (sender, e) =>

            {

                taskCompletionSource.TrySetResult(e.Position);

                dialog.Dismiss();

                dialog.Dispose();

            };

            dialog.CancelEvent += delegate {

                taskCompletionSource.TrySetResult(-1);

            };

            dialog.SetCanceledOnTouchOutside(true);

            dialog.Show();

            return taskCompletionSource.Task;

        }

 

Create a custom adapter

public class MyTestViewModelAdapter : ArrayAdapter<MyTestViewModel>

    {

        readonly MyTestViewModel[] _options;

        public MyTestViewModelAdapter(Context context, int textViewResourceId, AcceptTimeOptionViewModel[] options) : base(context, textViewResourceId, options)

        {

            _options = options;

        }

        public override View GetView(int position, View convertView, ViewGroup parent)

        {

            View view = convertView;

            if (view == null)

            {

                var vi = (LayoutInflater)Context.GetSystemService(Context.LayoutInflaterService);

                view = vi.Inflate(Resource.Layout.Include_AcceptTime, null);

            }

            MyTestViewModel option = _options[position];

            if (option != null)

            {

                var text1 = (TextView)view.FindViewById(Resource.Id.text1);

                if (text1 != null)

                {

                    text1.Text = option.SomeString;

                }

            }

            return view;

        }

........and there you have it. Customise your dialog axml and rowlayout axml to your hearts content.