使用Checkbox的Listview正在检查多个复选框

时间:2016-09-22 22:15:00

标签: android listview checkbox xamarin.android android-arrayadapter

所以我一直在开发一个带有复选框的列表视图的应用程序,当我选择一个项目后,当我向下滚动第一个项目时,我注意到列表中的第一个项目向下滚动整页也会选中复选框。我有一种感觉,这是由于重新评估的观点,但我对此解决方案感到好奇。我曾尝试添加一个视图,但这并没有解决问题。只是想知道我错过了什么。适配器上的getview代码如下:

        public override Android.Views.View GetView(int position, Android.Views.View convertView, ViewGroup parent)
        {
            Android.Views.View view = convertView;
            if (view == null)
            {
                view = context.LayoutInflater.Inflate(Resource.Layout.GroupTimeTrackerTemplate, parent, false);
            }
            tblWorkers item = this[position];

            view.FindViewById<TextView>(Resource.Id.UserNameTextView).Text = this[position].nWorkerFirstname + " " + this[position].nWorkerLastname;
            view.FindViewById<TextView>(Resource.Id.StatusTextView).Text = this[position].nStatusShort;
            view.FindViewById<TextView>(Resource.Id.UserRoleTextView).Text = this[position].nTitle;
            CheckBox chkSelect = view.FindViewById<CheckBox>(Resource.Id.ChkSelect);
            chkSelect.Tag = item.nWorkerFirstname + " " + item.nWorkerLastname;

            chkSelect.SetOnCheckedChangeListener(null);
            chkSelect.SetOnCheckedChangeListener(new CheckChangeListener(this.context));
            return view;
        }

        private class CheckChangeListener : Java.Lang.Object, CompoundButton.IOnCheckedChangeListener
        {

            private Activity activity;

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

            public void OnCheckedChanged(CompoundButton buttonView, bool isChecked)
            {
                if (isChecked)
                {
                    string name = (string)buttonView.Tag;
                    string text = string.Format("{0} Checked.", name);
                    Toast.MakeText(this.activity, text, ToastLength.Short).Show();
                }
            }
        }

3 个答案:

答案 0 :(得分:1)

我最终找到了一个具有可与我的动态模型数据一起使用的View Holder的解决方案。以下对我有用的是解决方案!三个要点是业务逻辑对象有一个bool来保持正在检查的项目和视图持有者帮助执行,最后由于视图的重新命名,你不能可靠地使用点击事件中的列表[位置]所以我使用了包装纸!

查看持有人:

    private class MyViewHolder : Java.Lang.Object
    {
        public TextView txtName;
        public TextView txtStatus;
        public TextView txtTitle;
        public CheckBox chkItem;

    }

适配器GetView:

    public override Android.Views.View GetView(int position, Android.Views.View convertView, ViewGroup parent)
    {

        var item = list[position];
        Android.Views.View view = convertView;
        MyViewHolder holder;
        if (convertView == null)
        {
            holder = new MyViewHolder();
            view = context.LayoutInflater.Inflate(Resource.Layout.GroupTimeTrackerTemplate, null);
            holder.chkItem = view.FindViewById<CheckBox>(Resource.Id.ChkSelect);
            holder.txtName = view.FindViewById<TextView>(Resource.Id.UserNameTextView);
            holder.txtStatus = view.FindViewById<TextView>(Resource.Id.StatusTextView);
            holder.txtTitle = view.FindViewById<TextView>(Resource.Id.UserRoleTextView);
            view.Tag = holder;
        }
        else
        {
            holder = view.Tag as MyViewHolder;

        }
        holder.chkItem.Checked = item.StatusSelected;
        if (holder.chkItem.Checked)
        {
            holder.chkItem.Enabled = false;
        }
        else
        {
            holder.chkItem.Enabled = true;
        }
        holder.chkItem.Tag = new MyWrapper<int>(position);
        holder.txtName.Text = item.nWorkerFirstname + " " + item.nWorkerLastname;
        holder.txtStatus.Text = item.nStatusShort;
        holder.txtTitle.Text = item.nTitle;
        holder.chkItem.Click -= HolderChkItemClick;
        holder.chkItem.Click += HolderChkItemClick;
        if (statoChk[position] == 0)
        {
            holder.chkItem.Checked = false;
        }
        else
        {
            holder.chkItem.Checked = true;
        }


        return view;
    }

单击“事件”复选框,包装器和数组:

    tblWorkers OrigSel = null;
    void HolderChkItemClick(object sender, EventArgs e)
    {
        var chk = sender as CheckBox;
        int pos = ((MyWrapper<int>)chk.Tag).value;
        tblWorkers selectedWorker = list[pos];
        if (Vm.SelectedWorker == null)
        {
            OrigSel = selectedWorker;
            IntentManager.Instance.OriginalSelectedWorker = OrigSel;
            Vm.GroupTimeTrackerStatusType = OrigSel.nStatusShort;
        }
        Vm.SelectedWorker = selectedWorker;
        if (chk.Checked)
        {
            if (selectedWorker.nStatusShort == OrigSel.nStatusShort)
            {
                statoChk[pos] = 1;
                Vm.GroupTimeList.Add(selectedWorker);
            }
            else
            {
                statoChk[pos] = 0;
                chk.Checked = false;
                Toast.MakeText(context, "Please Select Workers with the Same Time Status. Current Status : " + OrigSel.nStatusShort, ToastLength.Long).Show();
            }
        }
        else
        {
            statoChk[pos] = 0;
            Vm.GroupTimeList.Remove(selectedWorker);
            if (Vm.GroupTimeList.Count == 0)
            {
                Vm.SelectedWorker = null;
                OrigSel = null;
                IntentManager.Instance.OriginalSelectedWorker = null;
                Vm.GroupTimeTrackerStatusType = "";
            }
        }


    }

    public class MyWrapper<T> : Java.Lang.Object
    {
        private T _value;
        public MyWrapper(T managedValue)
        {
            _value = managedValue;
        }
        public T value { get { return _value; } }
    }


    int[] statoChk;
    public int[] StatoCheck
    {
        get { return statoChk; }
        set { statoChk = value; }
    }

答案 1 :(得分:0)

虽然我没有亲自通过Xamarin开发Android,但我拥有Android知识,可以帮助您朝着正确的方向发展。

正如您所说,ListView中的行已被回收。问题在于,当你滚动时,会调用OnCheckedChange方法,因为它会回收它在未选择的新行的位置传递的行,但由于它与之前选择的行具有相同的索引。改变它的价值。

例如,如果选中索引为5的方框然后向下滚动,则新行将成为索引为5的行,因此会更改其状态。

这是Android上的常见问题。要解决这个问题,首先需要一个数据结构,通过将其存储在地图或列表中来跟踪已经检查过哪些行。

然后在GetView中确保将复选框状态设置为该位置的内容。

答案 2 :(得分:0)

@Ivan Alburquerque是对的,这是因为Android会回收列表中的视图。您应该始终根据数据源的位置设置GetView方法上的复选框的值。 为了避免你在这里写的所有这些重复的代码,我建议你使用像MvvmCross(https://github.com/mvvmcross/mvvmcross)这样的MVVM框架为你做所有事情,你需要编写的代码将少得多。 玩得开心。