列表视图中的 CheckedTextView 在过滤器搜索后更改位置

CheckedTextView in listview changes position after filter search

我想在 android Xamarin 中实现多选列表。为此,我使用了带有 checkedTextview.

的自定义适配器

适配器class:

 public class FilterableMultiselectAdapter : ArrayAdapter, IFilterable, View.IOnClickListener
    {
        LayoutInflater inflater;
        Filter filter;
        Activity context;
        public List<FilterableListViewModel> AllItems;
        public List<FilterableListViewModel> MatchItems;

        public List<string> SelectedItems= new List<string>();
        private CheckedTextView _checkedText;

        public FilterableMultiselectAdapter(Activity context, int txtViewResourceId, List<FilterableListViewModel> items) : base(context, txtViewResourceId, items)
        {
            inflater = context.LayoutInflater;
            filter = new SuggestionsFilter(this);
            AllItems = items;
            MatchItems = items;
        }

        public override int Count
        {
            get
            {
                return MatchItems.Count;
            }
        }

        public override Java.Lang.Object GetItem(int position)
        {
            return null;
        }

        public FilterableListViewModel GetMatchedItem(int position)
        {
            return MatchItems[position];
        }

        public List<string> SelectedItemsList()
        {
            return SelectedItems;
        }


        public override View GetView(int position, View convertView, ViewGroup parent)
        {
            View view = convertView;
            if (view == null)
                view = inflater.Inflate(Resource.Drawable.filterMultiselectList_view, null);

            _checkedText = view.FindViewById<CheckedTextView>(Resource.Id.chkTV);

            _checkedText.Text = MatchItems[position].displayName;
            _checkedText.SetOnClickListener(this);

            return view;
        }


        public void OnClick(View V)
        { 
            if (((CheckedTextView)V).Checked)
            {
                // set check mark drawable and set checked property to false
               // value = "un-Checked";
                ((CheckedTextView)V).SetCheckMarkDrawable(0);
                ((CheckedTextView)V).Checked = (false);

            }
            else
            {
                // set cheek mark drawable and set checked property to true
                // value = "Checked";
                ((CheckedTextView)V).SetCheckMarkDrawable(Resource.Drawable.ic_check);
                ((CheckedTextView)V).Checked = (true);
                addItemIntoCheckedList(((CheckedTextView)V).Text);
            }
        }

        private void addItemIntoCheckedList(string id)
        {


            SelectedItems.Add(id);

        }

        public override Filter Filter
        {
            get
            {
                return filter;
            }
        }

        public void ResetSearch()
        {
            MatchItems = AllItems;
            NotifyDataSetChanged();
        }

        class SuggestionsFilter : Filter
        {
            readonly FilterableMultiselectAdapter _adapter;

            public SuggestionsFilter(FilterableMultiselectAdapter adapter) : base()
            {
                _adapter = adapter;
            }

            protected override Filter.FilterResults PerformFiltering(Java.Lang.ICharSequence constraint)
            {
                FilterResults results = new FilterResults();
                if (!String.IsNullOrEmpty(constraint.ToString()))
                {
                    var searchFor = constraint.ToString();
                    Console.WriteLine("searchFor:" + searchFor);
                    var matchList = new List<FilterableListViewModel>();
                    //var matches = _adapter.AllItems.Where(i => i.title.ToLower().Contains(searchFor.ToLower()) || string.IsNullOrEmpty(i.subText) ? 1 == 1 : i.subText.ToLower().Contains(searchFor.ToLower()));

                    var matches = _adapter.AllItems.Where(i => i.item.ToLower().Contains(searchFor.ToLower()));// || (i.subItem != null && i.subItem.ToLower().Contains(searchFor.ToLower())));//   !string.IsNullOrEmpty(i.subText) ? i.subText.ToLower().Contains(searchFor.ToLower()) : null);


                    foreach (var match in matches)
                    {
                        matchList.Add(match);
                    }

                    _adapter.MatchItems = matchList;
                    Console.WriteLine("resultCount:" + matchList.Count);

                    List<FilterableListViewModel> matchObjects = new List<FilterableListViewModel>();
                    for (int i = 0; i < matchList.Count; i++)
                    {
                        matchObjects.Add(matchList[i]);
                    }

                    results.Count = matchList.Count;
                }
                else
                {
                    _adapter.ResetSearch();
                }
                return results;
            }

            protected override void PublishResults(Java.Lang.ICharSequence constraint, Filter.FilterResults results)
            {
                _adapter.NotifyDataSetChanged();
            }
        }
    }

这里的问题是,假设我的列表中有 4 个项目,我选择了第一个和第二个项目,然后我去搜索可以给我剩余列表的东西,然后复选框的选择不能正常工作.

我试图找出问题所在,但无法解决该问题。我在 上发现了类似的问题,但它的解决方案指向 android library.I cannot use android library as I am using Xamarin android。

如果有人已经解决了这个问题,请帮助我。

您在单独的列表 SelectedItems 中管理所选项目,因此当 MatchItems 的内容更改 SelectedItems 变得过时而不是单独管理它时,请在您的列表中定义一个 boolean模型 MatchItems isSelected/isChecked 并更新它 onclick()

我不是 Xamarin 开发人员,但我可以看出您的代码未优化。例如,您不需要使用成员变量 private CheckedTextView _checkedText;,而是使用 method-scope/local 变量。您可能希望查看 ViewHolder 模式以优化内存使用和性能。要解决您的问题,请检查代码片段中的 // TODO 注释,首先这里存在逻辑错误:

public void OnClick(View V)
{ 
    if (((CheckedTextView)V).Checked)
    {
        // set check mark drawable and set checked property to false
       // value = "un-Checked";
        ((CheckedTextView)V).SetCheckMarkDrawable(0);
        ((CheckedTextView)V).Checked = (false);
        // TODO I believe you should remove your item from SelectedItems
        SelectedItems.Remove(((CheckedTextView)V).Text);
    }
    else
    {
        // set cheek mark drawable and set checked property to true
        // value = "Checked";
        ((CheckedTextView)V).SetCheckMarkDrawable(Resource.Drawable.ic_check);
        ((CheckedTextView)V).Checked = (true);
        addItemIntoCheckedList(((CheckedTextView)V).Text);
    }
}

然后在方法 GetView 上,您应该检查 id/text 是否存在于 SelectedItems 列表

public override View GetView(int position, View convertView, ViewGroup parent)
{
    View view = convertView;
    if (view == null)
        view = inflater.Inflate(Resource.Drawable.filterMultiselectList_view, null);

    _checkedText = view.FindViewById<CheckedTextView>(Resource.Id.chkTV);

    _checkedText.Text = MatchItems[position].displayName;
    _checkedText.SetOnClickListener(this);
    // TODO check if the item is checked based on the id you have saved
    // something like this:
    if (SelectedItems.Contains(_checkedText.Text)) {
        _checkedText.Checked = true;
        _checkedText.SetCheckMarkDrawable(Resource.Drawable.ic_check);
    }
    else {
        _checkedText.Checked = false;
        _checkedText.SetCheckMarkDrawable(0);   
    }
    return view;
}