Listview with checkboxes in monodroid

kishukishu INMember ✭✭

I have created one list view with check boxes but the problem is checkbox checked state is not appearing.
Here is my code,here am having checkbox.

<?xml version="1.0" encoding="utf-8"?>






And Here am having listview,

<?xml version="1.0" encoding="utf-8"?>



And my adapter is,

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;

namespace EventNotifier.AndroidUI
{
class SearchGroupAdapter: BaseAdapter {
List items;
Activity context;
public SearchGroupAdapter(Activity context,int resourceId, List items) : base()
{
this.context = context;
this.items = items;
}
public override long GetItemId(int position)
{
return position;
}
public override Group this[int position]
{
get { return items[position]; }
}
public override int Count
{
get { return items.Count; }
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
var item = items[position];
View view = convertView;

        if (view == null) // no view to re-use, create new
            view = context.LayoutInflater.Inflate(Resource.Layout.SearchGroupCell, null);

        view.FindViewById<TextView> (Resource.Id.Text2).Text = item.Name;
        return view;
    }
}

}

Here is Listview code,

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;

namespace EventNotifier.AndroidUI
{
[Activity (Label = "SearchGroup")]
public class SearchGroupList :Activity
{
ListView listView;
Button btnSubscribe;
CheckBox chkGroup;
private SearchGroupAdapter searchGroupAdapter;
public List groups = new List ();
protected override void OnCreate (Bundle bundle)
{

        base.OnCreate (bundle);
        SetContentView (Resource.Layout.SearchGroup);
        listView = FindViewById<ListView>(Resource.Id.searchList); // get reference to the ListView in the layout
        btnSubscribe = FindViewById<Button>(Resource.Id.btnSubscribe);

        groups.Add(new Group() {  Id = 1, Name = "TANA", Image = "Test Image"});
        groups.Add(new Group() {  Id = 2, Name = "OASSIS", Image = "Test Image"});
        groups.Add(new Group() {  Id = 3, Name = "KALA", Image = "Test Image"});
        groups.Add(new Group() {  Id = 4, Name = "MANCA", Image = "Test Image" });
        groups.Add(new Group() {  Id = 5, Name = "MAITHRY", Image = "Test Image" });
        groups.Add(new Group() {  Id = 6, Name = "ORUMA", Image = "Test Image" });
        groups.Add(new Group() {  Id = 7, Name = "OASSIS", Image = "Test Image" });
        groups.Add(new Group() {  Id = 8, Name = "MANCA", Image = "Test Image" });

        // populate the listview with data
        searchGroupAdapter=new SearchGroupAdapter(this,Android.Resource.Layout.SimpleListItemMultipleChoice, groups);
        listView.Adapter = searchGroupAdapter;
        listView.ChoiceMode = Android.Widget.ChoiceMode.Multiple;

        listView.ItemClick += OnListItemClick;  
        btnSubscribe.Click += OnbtnSubscribeClik;   
        chkGroup= FindViewById<CheckBox> (Resource.Id.chkGroup);
        //chkGroup.SetOnCheckedChangeListener += OnCheckedChanged;
    }

    protected void OnListItemClick(object sender,Android.Widget.AdapterView.ItemClickEventArgs e)
    {           
        var listView = sender as ListView;
        var t = groups[e.Position];

        //var chkGroup= FindViewById<CheckBox> (Resource.Id.chkGroup);
        //chkGroup.Checked = true;
    }


    //protected void OnCheckedChanged(CompoundButton buttonView,bool isChecked)
    //{
    //  if (buttonView.Checked) {
    //      Toast.MakeText (this, "selected", ToastLength.Short).Show ();
    //  }
    //  else
    //  {
    //      Toast.MakeText (this, "not selected", ToastLength.Long).Show ();
    //  }
    //}

    protected void OnbtnSubscribeClik(object sender,EventArgs e)
    {
        var myListView = FindViewById<ListView>(Resource.Id.searchList);
        var sparseArray = FindViewById<ListView>(Resource.Id.searchList).CheckedItemPositions;

        for (var i = 0; i < sparseArray.Size(); i++) 
        {
            string selectedValue=string.Empty;
            int position = sparseArray.KeyAt(i);
            var currentItem =listView.Adapter.GetItem(position);
            if (sparseArray.ValueAt (i) == true) 
            {
                selectedValue = groups [position].Name;
                //groups.Remove (groups [position]);
                Android.Widget.Toast.MakeText(this,"Subscribed for "+selectedValue, Android.Widget.ToastLength.Short).Show();
                //searchGroupAdapter.NotifyDataSetChanged ();
            }

            //listView.Adapter = new SearchGroupAdapter(this,Android.Resource.Layout.SimpleListItemMultipleChoice, groups);
        }
        Console.WriteLine();
    }
}

}

And some of links i have seen some of links,they are giving solution like onCheckedChanged method but am unable to implement that.
please help me.

Posts

  • This is happening because of the caching of the view on the ListView. To achieve this I had to create a viewholder as a Java.Lang.Object and have it set as the tag for convertView. I've listed my code here, hopefully it's not too difficult for you to implement this for what you need... Sorry if it is!!

    Here is my code for GetView:

        public override View GetView(int position, View convertView, ViewGroup parent)
        {
            var thisRow = _mainlist[position];
            CheckBox checkBox;
            TextView receiptDate;
            TextView receiptTime;
            TextView receiptNumber;
            TextView debtorName;
            TextView caseReference;
            TextView amountPaid;
            TextView paymentType;
    
            TextView bankingLabel;
            TextView bankingDate;
            TextView bankingReference;
    
            #region Prepare view
    
            if (convertView == null)
            {
                convertView = _act.LayoutInflater.Inflate(Resource.Layout.bankingRow, null);
                receiptDate = convertView.FindViewById<TextView>(Resource.Id.txtDate);
                receiptTime = convertView.FindViewById<TextView>(Resource.Id.txtTime);
                receiptNumber = convertView.FindViewById<TextView>(Resource.Id.txtReceiptNumber);
                debtorName = convertView.FindViewById<TextView>(Resource.Id.txtDebtorName);
                caseReference = convertView.FindViewById<TextView>(Resource.Id.txtReference);
                amountPaid = convertView.FindViewById<TextView>(Resource.Id.txtPaymentAmount);
                paymentType = convertView.FindViewById<TextView>(Resource.Id.txtPaymentType);
    
                bankingLabel = convertView.FindViewById<TextView>(Resource.Id.lblBanked);
                bankingDate = convertView.FindViewById<TextView>(Resource.Id.txtBankedDate);
                bankingReference = convertView.FindViewById<TextView>(Resource.Id.txtBankRef);
                checkBox = convertView.FindViewById<CheckBox>(Resource.Id.chChecked);
    
                convertView.Tag = new BankViewHolder(checkBox, receiptDate, receiptTime, receiptNumber, debtorName,
                                                     caseReference, amountPaid, paymentType, bankingLabel, bankingDate,
                                                     bankingReference); 
                checkBox.Click += (o, e) =>
                    {
                        var cb = (CheckBox)o;
                        var item = (BankItem)cb.Tag;
                        item.Checked = cb.Checked;
                    };
            }
            else
            {
                var holder = (BankViewHolder)convertView.Tag;
                checkBox = holder.CheckBox;
                receiptDate = holder.ReceiptDate;
                receiptTime = holder.ReceiptTime;
                receiptNumber = holder.ReceiptNumber;
                debtorName = holder.DebtorName;
                caseReference = holder.CaseReference;
                amountPaid = holder.AmountPaid;
                paymentType = holder.PaymentType;
    
                bankingLabel = holder.BankingLabel;
                bankingDate = holder.BankingDate;
                bankingReference = holder.BankingReference;
            }
    
    
    
    
    
            if (_showBanking)
            {
                bankingLabel.Visibility = ViewStates.Visible;
                bankingDate.Visibility = ViewStates.Visible;
                bankingReference.Visibility = ViewStates.Visible;
    
                var bankDate = _mainlist[position].Receipt.BankDate;
                if (bankDate != null)
                    bankingDate.Text = bankDate.Value.ToString("dd/MM/yyyy");
                bankingReference.Text = _mainlist[position].Receipt.BankReference;
            }
            else
            {
                bankingLabel.Visibility = ViewStates.Invisible;
                bankingDate.Visibility = ViewStates.Invisible;
                bankingReference.Visibility = ViewStates.Invisible;
            }
    
    
            checkBox.Focusable = false;
            checkBox.FocusableInTouchMode = false;
            checkBox.Tag = thisRow;
            checkBox.Checked = _mainlist[position].Checked;
    
    
    
            receiptDate.Text = _mainlist[position].ReceiptParameters.ReceiptDateTime.ToString("dd/MM/yyyy");
            receiptTime.Text = _mainlist[position].ReceiptParameters.ReceiptDateTime.ToString("hh:mm tt");
            receiptNumber.Text = _mainlist[position].ReceiptParameters.ReceiptNumber;
            debtorName.Text = _mainlist[position].ReceiptParameters.DebtorName;
            caseReference.Text = _mainlist[position].ReceiptParameters.Reference;
            amountPaid.Text = _mainlist[position].ReceiptParameters.PaymentDetails.Amount.ToString("c");
            paymentType.Text = _mainlist[position].ReceiptParameters.PaymentDetails.PaymentType;
    
            #endregion
    
    
            return convertView;
        }
    

    Notice setting the focusable and focusableInTouchMode to false - this is possible in the XML but I'm lazy so did it this way... lol. This prevents the checkbox focusing and instead runs the list item's ItemClick

    The mainlist there is a list of objects that I created to hold the receipt details and whether the row was checked. Below is my code for the view holder and the bank items:

        private class BankViewHolder : Java.Lang.Object
        {
            public CheckBox CheckBox;
    
            public TextView ReceiptDate,
                            ReceiptTime,
                            ReceiptNumber,
                            DebtorName,
                            CaseReference,
                            AmountPaid,
                            PaymentType,
                            BankingLabel,
                            BankingDate,
                            BankingReference;
    
            public BankViewHolder()
            {
            }
            public BankViewHolder(CheckBox cb, TextView receiptDate,TextView receiptTime,TextView receiptNumber,TextView debtorName,
                TextView caseReference,TextView amountPaid,TextView paymentType,TextView bankingLabel,TextView bankingDate,
                TextView bankingReference)
            {
                CheckBox = cb;
                ReceiptDate = receiptDate;
                ReceiptNumber = receiptNumber;
                ReceiptTime = receiptTime;
                DebtorName = debtorName;
                CaseReference = caseReference;
                AmountPaid = amountPaid;
                PaymentType = paymentType;
                BankingLabel = bankingLabel;
                BankingDate = bankingDate;
                BankingReference = bankingReference;
            }
        }
    }
    
    public class BankItem : Java.Lang.Object
    {
        internal readonly CompletedReceipt Receipt;
        internal readonly ReceiptParameters ReceiptParameters;
        internal bool Checked;
    
        public BankItem()
        {
        }
    
        internal BankItem(CompletedReceipt cr)
        {
            Receipt = cr;
            ReceiptParameters = new ReceiptParameters(XElement.Parse(StringCipher.Decrypt(cr.EncData, cr.Reference)));
        }
    
        public BankItem(CompletedReceipt cr, bool check)
        {
            Receipt = cr;
            ReceiptParameters = new ReceiptParameters(XElement.Parse(StringCipher.Decrypt(cr.EncData, cr.Reference)));
            Checked = check;
        }
    
        internal void Toggle()
        {
            Checked = !Checked;
        }
    }
    

    I also wanted clicking the list item to check/uncheck the box so the code on the ItemClick then just calls this method in my adapter:

        public void PerformClick(int position)
        {
            var item = _mainlist[position];
            item.Toggle();
            NotifyDataSetChanged();
        }
    

    I know it's a lot of work and it seems like it's a hack, but using view holders actually marginally improves performance of listviews too - it's a good habit to get into when dealing with lists with lots of views on the row

Sign In or Register to comment.