【问题标题】:Listview with Checkbox is checking more than one checkbox带有 Checkbox 的 Listview 正在检查多个复选框
【发布时间】:2017-01-31 15:51:23
【问题描述】:

所以我一直在开发一个带有带有复选框的列表视图的应用程序,我注意到当我选择一个项目时,当我在向下滚动一整页后向下滚动第一项时说列表中的第一项具有复选框也被选中。我有一种感觉,这是由于再循环的观点,但我很好奇这个解决方案。我曾尝试添加一个查看器,但这并没有解决问题。只是想知道我错过了什么。适配器上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();
                }
            }
        }

【问题讨论】:

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


    【解决方案1】:

    虽然我个人没有通过 Xamarin 开发过 Android,但我拥有的 Android 知识可以帮助您找到正确的方向。

    正如您正确陈述的那样,ListView 中的行被回收。问题是,当您滚动时,将调用 OnCheckedChange 方法,并且由于它回收了它在未选择的新行的位置传递的行,但由于它具有与先前选择它的索引相同的索引改变它的价值。

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

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

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

    【讨论】:

    • 我已经完成了 Java 和 C#,它们非常相似,但在 Xamarin 上并没有很多像 Android 那样的示例。令人困惑的是,我使用的是我传入的实际列表,即 ObervableCollection,所以位置应该不是问题,但我想它是。你能举个Java的例子吗?
    【解决方案2】:

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

    【讨论】:

    • 那你为什么要手动设置值,而不是绑定到源,然后将 CheckBox 的状态绑定到 ViewModel 中的值?
    • 我绑定到源,但业务逻辑的自定义性质要求我必须手动执行此操作。
    • 抱歉,但在您的适配器上,我没有看到任何特别之处。我认为 MvvmCross 提供了更多的灵活性,我已经完全习惯了,即使有很多复杂的数据要绑定,我也从不编写适配器。
    • 我认为你没有抓住重点。 #1 我正在使用 mvvm light。 #2 我的数据是高度动态的,我已经在适配器中删除了这些部分。
    • 我知道你在用什么。使用 Mvvm 框架通常意味着无需适配器即可直接绑定数据。但是,如果我再次检查您的问题,只需在复选框被选中或不是每个类型的情况下分配值,您返回的视图应该可以解决您的问题。检查 mvvmcross 上的 aome binsings,你会看到我的意思是直接绑定,即使是具有多种不同布局的复杂数据。
    【解决方案3】:

    我最终找到了一个解决方案,该解决方案具有一个适用于我的动态模型数据的 View Holder。这对我有用,下面是解决方案!三个要点是业务逻辑对象有一个 bool 来保存被检查的项目和视图持有者有助于提高性能,最后由于视图的回收,你不能在点击事件中可靠地使用 list[position] 所以我使用了包装器!

    查看持有人:

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

    适配器获取视图:

        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; }
        }
    

    【讨论】:

      猜你喜欢
      • 2016-02-14
      • 2015-11-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-20
      • 1970-01-01
      • 2020-09-07
      • 2012-11-02
      相关资源
      最近更新 更多