Custom ListView with Xamarin Android

This post will demonstrate how to create custom listview with Xamarin Android tool. The example app used in this project is the concept of a professional Service. Imagine an Android app for a Handyman, a field technician or anyone who offers any kind of skilled service. The purpose of this example app is to show the list of service this person offers, in the case of the Handyman which is “a person skilled at a wide range of repairs, typically around the home” the services offered could be fixing toilet, kitchen repairs, light bulb replacement. In a subsequent post I will show how this app can be extended to support issuing invoices, today the focus is on custom listview. You can find the source code for this project at Github. Here is what the project we are creating will look like:

Create the Project

I am using Visual Studio 2013 update 4 with Xamarin Business edition. I am sure that you can use the Xamarin Starter edition as well and this will surely work in Xamarin Studio. The strength of the Xamarin offering is in code re-use or more frequently referred to as cross platform app development, however in this post, I am focusing on using Xamarin to create a native Android app with C# so I will not delve into code sharing concerns.

Whether you use Xamarin Studio or Visual Studio, create a Blank Android App, below is that this step looks like in Visual Studio. You can name it anything you want, I have named mine XamarinDroidCustomListView; and if you plan to follow along, you can go ahead and enable git source control so you can have adequate fall back.

Your new project should come with a MainActivity.cs, the same one you get with native Android development in Eclipse or Android Studio. The res folder in Android Studio is called Resources folder in Xamarin land.

Xamarin Project Structure

The project structure for Xamarin projects could be subjective but for the most part it is more predictive than native Android project. The Tasky Pro app/project is the Xamarin flagship reference project akin to ubiquitous Todo List app in Microsoft so I will the Tasky app stucture as a guide.

For now we will only need two folders: The DataAccess to hold our database file and data access files. We will also need a BusinessLayer folder to hold our business logic and contracts.

The focus of this app is a custom List of professional services, so I have named the main class to represent this concept ServiceItem.cs and the custom adapter that will be used to present this custom lists of this services I have named ServiceItemsAdapter.cs, my initial project structure looks like this

XML Layout for Custom ListView With Xamarin Android

We will need to create a custom listview for each row in our list. So go ahead and expand the Resource folder and under the layout sub folder go ahead and add an Android Layout file named CustomRow.axml; layout files have .axml in Xamarin instead of .xml in native Android.

It is possible that after adding this file you will not have intellisense support, you can close the file and re-open it again and open the source tab.

If you still do not have intellisense support you can follow the suggestion in this blog post on how to add intellisense support to Android .axml layout files. You can use the designer to create this layout or you can copy and paste the following code to the source tab of this file.

Custom Adapter

With the custom listview out of the way, we proceed to create a custom adapter. This custom adapter will extend a generic BaseAdapter of type ServiceItem. So lets go ahead and define properties for the ServiceItem.cs. This just captures the name, description, price and category of the Service being offerred.

   public class ServiceItem 
        public int Id { get; set; }
        public string Name { get; set; }
        public string Description { get; set; }
        public double Price { get; set; }
        public string Category { get; set; }

Open the ServiceItemAdapter.cs and copy and paste or type the following code and we will walk through the content of that code

public class ServiceItemsAdapter : BaseAdapter
        protected Activity Context = null;
        protected List ServiceItems;

        public ServiceItemsAdapter(Activity context, IEnumerable services )
            this.Context = context;
            this.ServiceItems = services.ToList();

        public override long GetItemId(int position)
            return position;

        public override int Count
                return ServiceItems.Count;

        public override ServiceItem this[int position]
            get { return ServiceItems[position]; }

        public override View GetView(int position, View convertView, ViewGroup parent)
            ServiceViewHolder holder = null;
            var view = convertView;

            if (view == null)
                //holder = new ServiceViewHolder();
                view = Context.LayoutInflater.Inflate(Resource.Layout.CustomRow, null);

                holder = new ServiceViewHolder();
                holder.Name = view.FindViewById(Resource.Id.tvServiceName);
                holder.Price = view.FindViewById(Resource.Id.tvServicePrice);
                holder.Category = view.FindViewById(Resource.Id.tvServiceCategory);
                holder.EditButton = view.FindViewById(Resource.Id.buttonEditService);
                holder.DeleteButton = view.FindViewById(Resource.Id.buttonDeleteService);

                view.Tag = holder;
                    holder = view.Tag as ServiceViewHolder;

            //Now the holder holds reference to our view objects, whether they are 
            //recycled or created new. 
            //Next we need to populate the views

            var tempServiceItem = ServiceItems[position];
            //var tempServiceItem = new ServiceItem();
            holder.Name.Text = tempServiceItem.Name;
            holder.Category.Text = tempServiceItem.Category;
            holder.Price.Text = String.Format("{0:C}", tempServiceItem.Price);

            holder.DeleteButton.Click += (object sender, EventArgs e) => {
            holder.EditButton.Click += (object sender, EventArgs e) =>
               //Todo - implement edit Service

            return view;
        private class ServiceViewHolder : Java.Lang.Object
            public TextView Name { get; set; }
            public TextView Price { get; set; }
            public TextView Category { get; set; }
            public ImageButton EditButton { get; set; }
            public ImageButton DeleteButton { get; set; }

        public void Add(ServiceItem service)

This adapter’s constructor accepts an Activty as context and a List of type ServiceItem. The GetItem and Count methods are self explanatory. The Add method accepts a ServiceItem object and adds it to the List of ServiceItems, for example if you get your List of items from the database, then you can loop through that List and call this method to add each item to the List and then call NotifyDataSetChanged on the adapter so it can notify all attached observers (the screen in this case) to refresh themselves. Now let us examine the Get View method.

Custom Adapter Get View Method

This is where we do the most work, we override this method to supply our custom view for each row in the listview. When this method is called, it is passed three parameters: the position of the view in focus, a View object called the convertView here and the parent ViewGroup. First we check to see if this view is null, otherwise – has this particular view been recycled. If it has not been recycled return it otherwise create a new one. James Montemagno provided a good explanation of the view recycling and the view holder pattern in this blog post

Since this is a custom adapter, creating a new view means that the OS will have to traverse the resource tree to find all the child view that make up our row. To minimize the cost of this FindViewById transactions we implement a holder pattern which is essentially a class that provides getter and setter properties that stores instances of our view elements so we can just reuse them. Either way, whether we recycled a view or we got it from the view holder, we need to set the text properties of the views with the properties of the ServiceItem represented by that row. For example we need to set the Text property of the Name TextView with the Name property of the ServiceItem instance. And we get the instance of that ServiceItem by retrieving it from the List using the passed-in position parameter like so: var tempServiceItem = ServiceItems[position].

Main Activity – Display the Custom ListView

The last step is to use our custom adapter to display the custom listview. We do this from the Main Activity or any activity, you can either inherit from ListActivity which will expose a ListView property or you can create an instance of the listview like I did below:

Activity(Label = "Xamarin Droid Custom ListView", MainLauncher = true, Icon = "@drawable/icon")]
    public class MainActivity : Activity
        protected ListView MyServiceListView;
        protected List MyServiceItems;
        protected ServiceItemsAdapter MyServiceItemsAdapter;
        public static readonly string Tag = typeof (MainActivity).ToString();

        protected override void OnCreate(Bundle bundle)

            // Set our view from the "main" layout resource

            MyServiceListView = FindViewById(Resource.Id.service_list);

            //Create an empty list of Service List
            MyServiceItems = (List) ServicesManager.GetServiceItems();
            MyServiceItemsAdapter = new ServiceItemsAdapter(this, MyServiceItems);

            MyServiceListView.Adapter = MyServiceItemsAdapter;
            var emptyText = FindViewById(Resource.Id.service_list_empty);
            MyServiceListView.EmptyView = emptyText;


        protected override void OnResume()
           // LoadData();

        private void LoadData()
            //First clear the adapter of any Services it has 
           // MyServiceItemsAdapter.NotifyDataSetInvalidated();

            Log.Info("LoadData", "Creating Service Instance");
            var service1 = new ServiceItem
                Name = "Baby Sitting Service",
                Description = "Caring baby sitting service",
                Price = 75,
                Category = "Domestic"
           var result = ServicesManager.SaveServiceItem(service1);
            Log.Info(Tag," First insert " + result);

            var service2 = new ServiceItem
                Name = "House painting",
                Description = "Great looking paint service",
                Price = 150,
                Category = "Labor"

           var result2 = ServicesManager.SaveServiceItem(service2);
           Log.Info(Tag, " First insert " + result2);

As you can see, I create an empty List and instantiate the adapter with this list, you create a seperate method that actually loads the data and call this method from the OnResume. This is important because you can ensure the screen is updated in onResume events like screen rotation. For now I just create two in memory ServiceItems and called the adapter.Add method to add them. If you run it now, you should be able to see your custom listview if not study the error message and post your questions here or other forums.
Coming up next, I will write a post that shows how to save the data to SQLite database using ORM.


About the Author valokafor

I am a Software Engineer with expertise in Android Development. I am available for Android development projects.

follow me on:

Leave a Comment: