Introduction
For most Xamarin.Android
applications you will want to display data of some sort. That may be data from a database, XML or other technology. If you have developed Windows or Web applications using the .NET Framework. then you will be familiar with using UI controls and populating these controls at runtime from data from different sources. Android similarly allows the developer to populate UI controls with data, but there are differences in how you achieve this using Android. The purpose of this article is to show you how you can populate an Android UI control with data using Xamarin.Android
and Visual Studio
.
Assumptions
For the purposes of this article I will assume the reader is familiar with creating Android screen layouts and implementing classes in C#.
Background
The Adapter
class is the bridge between the UI control and the data source. In the world of Android development, all UI controls are collectively referred to as a View
. A View
is the basic building block for all UI components. The Adapter
class returns an instance of a View
. When used to display a list of items, the Adapter
will return a single View
for each data item i.e. a View
is returned for each row in the list of items.
The developer is able to manipulate the representation of the data before it is displayed. For example if the data contains a BIT
type to represent a True / False condition, the developer can return the words TRUE or FALSE from the View
rather than displaying it's raw BIT
value.
Very simple Adapter example - A list of items
The following example demonstrates how to display a very simple list of items.
- Description
- Make
- Model
- Quantity
To keep the article nice and simple I will use XML data to populate the list. Here is a sample of the underlying XML.
<GOODS>
<GOOD>
<DESCRIPTION>Description1</DESCRIPTION>
<MAKE>Item1</MAKE>
<MODEL>Model1</MODEL>
<QUANTITY>1</QUANTITY>
</GOOD>
<GOOD>
<DESCRIPTION>Description2</DESCRIPTION>
<MAKE>Item2</MAKE>
<MODEL>Model2</MODEL>
<QUANTITY>2</QUANTITY>
</GOODS>
The data consists of a list of goods. Each goods item has an associated description, make, model and quantity.
Creating the screen
Firstly we will need a screen to display our list of items. Here is a screenshot of how the screen looks in the designer in Visual Studio.
Here is the Android XML (AXML) code listing for the ListView
element i.e. the View
that will actually render the list of goods to the screen.
<ListView
p1:minWidth="25px"
p1:minHeight="25px"
p1:layout_width="match_parent"
p1:layout_height="match_parent"
p1:textAppearance="?android:attr/textAppearanceMedium"
p1:layout_below="@id/textView1"
p1:id="@+id/GoodsList" />
Here is the complete screen layout (AXML) listing showing the column headings and other UI elements.
="1.0"="utf-8"
<LinearLayout xmlns:p1="http://schemas.android.com/apk/res/android"
p1:orientation="vertical"
p1:minWidth="25px"
p1:minHeight="25px"
p1:id="@+id/Goods"
p1:layout_width="fill_parent"
p1:layout_height="fill_parent">
<RelativeLayout
p1:minWidth="25px"
p1:minHeight="25px"
p1:layout_width="wrap_content"
p1:layout_height="fill_parent"
p1:id="@+id/relativeLayout1"
p1:padding="5dp"
p1:layout_weight="0.5">
<Button
p1:text="Next"
p1:layout_width="wrap_content"
p1:layout_height="wrap_content"
p1:id="@+id/btnListGoods"
p1:drawableRight="@android:drawable/ic_media_next"
p1:layout_alignParentBottom="true"
p1:layout_alignParentRight="true" />
<TextView
p1:text="List of Goods"
p1:textAppearance="?android:attr/textAppearanceLarge"
p1:id="@+id/textView1"
p1:layout_width="wrap_content"
p1:layout_height="wrap_content" />
<ListView
p1:minWidth="25px"
p1:minHeight="25px"
p1:layout_width="match_parent"
p1:layout_height="match_parent"
p1:textAppearance="?android:attr/textAppearanceMedium"
p1:layout_below="@id/textView1"
p1:id="@+id/GoodsList" />
<TextView
p1:text="Description"
p1:textAppearance="?android:attr/textAppearanceSmall"
p1:layout_width="wrap_content"
p1:layout_height="wrap_content"
p1:layout_toRightOf="@id/textView2"
p1:id="@+id/textView2"
p1:layout_marginTop="35.2dp" />
<TextView
p1:text="Make"
p1:textAppearance="?android:attr/textAppearanceSmall"
p1:layout_width="wrap_content"
p1:layout_height="wrap_content"
p1:layout_toRightOf="@id/textView2"
p1:id="@+id/textView3"
p1:layout_marginTop="35.2dp"
p1:layout_marginLeft="129.1dp" />
<TextView
p1:text="Model"
p1:textAppearance="?android:attr/textAppearanceSmall"
p1:layout_width="wrap_content"
p1:layout_height="wrap_content"
p1:layout_toRightOf="@id/textView3"
p1:id="@+id/textView4"
p1:layout_marginTop="35.2dp"
p1:layout_marginLeft="167.5dp" />
<TextView
p1:text="Serial Numer"
p1:textAppearance="?android:attr/textAppearanceSmall"
p1:layout_width="wrap_content"
p1:layout_height="wrap_content"
p1:layout_toRightOf="@id/textView4"
p1:id="@+id/textView5"
p1:layout_marginTop="35.2dp"
p1:layout_marginLeft="159.4dp" />
<TextView
p1:text="Characteristics"
p1:textAppearance="?android:attr/textAppearanceSmall"
p1:layout_width="wrap_content"
p1:layout_height="wrap_content"
p1:layout_toRightOf="@id/textView5"
p1:id="@+id/textView6"
p1:layout_marginTop="35.2dp"
p1:layout_marginLeft="116.3dp" />
<TextView
p1:text="Quantity"
p1:textAppearance="?android:attr/textAppearanceSmall"
p1:layout_width="wrap_content"
p1:layout_height="wrap_content"
p1:layout_toRightOf="@id/textView6"
p1:id="@+id/textView7"
p1:layout_marginLeft="85.8dp"
p1:layout_marginTop="35.2dp" />
</RelativeLayout>
</LinearLayout>
Creating the goods list classes
Next we need to implement the Good
and Goods
classes as these will form the basis of the article. The Good
class represents a single item that will appear in the list. The Goods
class represents a list of Good
objects i.e. List<Good>
public class Good
{
public string Description;
public string Make;
public string Model;
public int Quantity = 1;
public Good()
{
}
}
public class Goods : List<Good>
{
public Goods()
{
}
public Goods(XElement xRoot)
{
if (xRoot == null || !xRoot.HasElements) return;
var xGoodList = xRoot.Descendants().ToList();
foreach (Good cg in xGoodList.Select(xGood => new Good(xGood)).Where(cg => !string.IsNullOrEmpty(cg.Description)))
{
Add(cg);
}
}
}
We now have a screen layout that can display a list of goods and we have class definitions for the Good
and Goods
classes which will be used to populate the list that is displayed on the screen layout.
Creating the Adapter class
We now need to define an Adapter
. As already mentioned, the Adapter
is the bridge between the UI View
element and the underlying XML data. In this example the Adapter
will act as the bridge between our XML data and ListView
.
We will derive our Adpater
class from the Android BaseAdapter
class which is the common base class for all Adapter
classes.
using System;
using System.Collections.Generic;
using System.Globalization;
using Android.App;
using Android.Graphics;
using Android.Views;
using Android.Widget;
using Application.Model;
namespace Application.Adapters
{
public class GoodsAdapter : BaseAdapter<Good>
{
private readonly List<Good> _list;
private readonly Activity _context;
public GoodsAdapter(Activity context, List<Good> list)
{
_context = context;
_list = list;
}
public List<Good> GetList()
{
return _list;
}
public override long GetItemId(int position)
{
return position;
}
public override int Count
{
get { return _list.Count; }
}
public override Good this[int position]
{
get { return _list[position]; }
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
TextView view = new TextView(_context);
const string space = " ";
string description = this[position].Description.PadRight(25, Convert.ToChar(space)).Substring(0, 25);
string make = this[position].Make.PadRight(25, Convert.ToChar(space)).Substring(0, 25);
string model = this[position].Model.PadRight(25, Convert.ToChar(space)).Substring(0, 25);
string quantity = this[position].Quantity.ToString(CultureInfo.InvariantCulture).PadRight(5, Convert.ToChar(space)).Substring(0, 5);
var bgColor = position % 2 == 0
? Color.White
: Color.LightGray;
view.SetBackgroundColor(bgColor);
view.SetTextColor(Color.Black);
view.SetTypeface(Typeface.Monospace, TypefaceStyle.Bold);
view.SetHeight(50);
view.Text = description +
make +
model +
quantity;
return view;
}
}
}
Things to note about our Adapter
class.
- The class is derived from
BaseAdapter
- The list of goods and application context are passed in via the constructor and stored as class properties (
_list
and _context
respectively) - The
GetView()
method is the primary method responsible for returning a single View
instance for each item in the list i.e. one row in the list is returned by this method
Populate the list of goods
The only remaining step is to populate the Adapter
with XML data and diiplay the list of items on the screen. You could add code similar to the following to your Activity
or Fragment
class to achieve this.
Goods _goods = new XElement(xRoot);
var adapter = new GoodsAdapter(Activity, _goods);
var viewGoods = Activity.FindViewById<ListView>(Resource.Id.GoodsList);
viewGoods.Adapter = adapter;
Summary
Hopefully this article has given you sufficient information for you to start creating your own Adapter
classes in your Xamarin.Android
application. Feel free to leave a comment if you would like me to further elaborate on anything within this article.