Search

Xamarin Android ListViews–Buttons on List Items

Thursday 9 October 2014

In this post we look at how to show a button on each item in a list, and how to handle click on both the list item and the button. The source code for the example is available here.

The first thing to do is to add a button to the item layout:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="25px"
    android:minHeight="25px"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/relativeLayout1"
    android:padding="4dp">
    <TextView
        android:text="txtName"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/txtName" />
    <TextView
        android:text="txtTeam"
        android:textAppearance="?android:attr/textAppearanceSmall"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/txtName"
        android:id="@+id/txtTeam"
        android:layout_alignLeft="@+id/txtName" />
    <Button
        android:text="Button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/txtTeam"
        android:id="@+id/button1" />
</RelativeLayout>


And you also need to update the adapter to handle button clicks. Here’s the full adapter code…

private class ButtonAdapter : BaseAdapter<Player>
{
    private Activity activity;
    private List<Player> data;

    public ButtonAdapter(Activity activity, List<Player> data)
    {
        this.activity = activity;
        this.data = data;
    }

    public override Player this[int position]
    {
        get { return this.data[position]; }
    }

    public override int Count
    {
        get { return this.data.Count(); }
    }

    public override long GetItemId(int position)
    {
        return 0;
    }

    public override View GetView(int position, View convertView, ViewGroup parent)
    {
        View view = convertView;

        if (view == null)
        {
            view = this.activity.LayoutInflater.Inflate(Resource.Layout.PlayerListItem3, null);
        }

        Player player = this.data[position];

        string name = player.Name;

        if (player.Captain)
        {
            name = string.Format("{0} (c)", name);
        }

        view.FindViewById<TextView>(Resource.Id.txtName).Text = name;
        view.FindViewById<TextView>(Resource.Id.txtTeam).Text = player.Team;

        Button button1 = view.FindViewById<Button>(Resource.Id.button1);
        button1.Tag = name;
        button1.SetOnClickListener(new ButtonClickListener(this.activity));

        return view;
    }

    private class ButtonClickListener : Java.Lang.Object, View.IOnClickListener
    {
        private Activity activity;

        public ButtonClickListener(Activity activity)
        {
            this.activity = activity;
        }

        public void OnClick(View v)
        {
            string name = (string)v.Tag;
            string text = string.Format("{0} Button Click.", name);
            Toast.MakeText(this.activity, text, ToastLength.Short).Show();
        }
    }
}


Here we’ve used a class that implements View.IOnClickListener to handle the clicks. Alternatively we could subscribe to the click event but then we would need to be careful to make sure that we only subscribe once for each button. As the item views are reused it’s easy to inadvertently subscribe to each button click multiple times. Using SetOnClickListener ensures that the click will only be handled once – it automatically replaces the old handler with the new one.


Handling Button Clicks & Item Clicks



Here’s the code for the activity – you can see that we have overridden OnListItemClick to show some toast.

[Activity(Label = "Custom Adapter")]
public class ButtonActivity : ListActivity
{
    protected override void OnCreate(Bundle bundle)
    {
        base.OnCreate(bundle);

        List<Player> players = Player.GetPlayers();
        this.ListAdapter = new ButtonAdapter(this, players);
    }

    protected override void OnListItemClick(ListView l, View v, int position, long id)
    {
        base.OnListItemClick(l, v, position, id);

        Player player = ((ButtonAdapter)this.ListAdapter)[position];
        string text = string.Format("{0} Item Click!", player.Name);
        Toast.MakeText(this, text, ToastLength.Short).Show();
    }
}


With the layout used above the OnListItemClick event won’t actually fire – to get it to fire we need to set focusable to false on the button like this:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="25px"
    android:minHeight="25px"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/relativeLayout1"
    android:padding="4dp">
    <TextView
        android:text="txtName"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/txtName" />
    <TextView
        android:text="txtTeam"
        android:textAppearance="?android:attr/textAppearanceSmall"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/txtName"
        android:id="@+id/txtTeam"
        android:layout_alignLeft="@+id/txtName" />
    <Button
        android:text="Button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/txtTeam"
        android:id="@+id/button1"
        android:focusable="false" />
</RelativeLayout>


Setting focusable to false stops the button from taking focus when you click on the ListItem and lets the OnListItemClick method run.


3 comments:

  1. Great extra tip and thank you for sharing on Xamarin Android ListViews–Buttons on List Items.

    Hire now DevRabbit, an authorized Xamarin partner and Xamarin consultant to Develop your Xamarin Apps.




    ReplyDelete