【问题标题】:Searching Through RecyclerView - Xamarin.Droid通过 RecyclerView 搜索 - Xamarin.Droid
【发布时间】:2017-07-09 16:16:20
【问题描述】:

我一直在寻找通过 recyclerView 搜索的 Xamarin 方式。任何人都可以向我介绍如何以 Xamarin 方式执行此操作的演示吗?

【问题讨论】:

  • 这里是关于如何在 Xamarin.Android 中使用 RecyclerView 的 documentdemo
  • @YorkShen 不是关于如何使用它,而是使用搜索图标过滤回收器视图:)

标签: c# android xamarin xamarin.android


【解决方案1】:

我写了一个关于如何实现这个功能的简单演示,效果类似于this。 你可以在这个GitHub Repository看到它。

有关更多信息,您可以阅读文档:Xamarin.Android 中的Filtering ListView with SearchViewXaver Kapeller's answer 关于过滤RecyclerViewSearchView

感谢 Xaver Kapeller 的回答,他关于 Searching Through RecyclerView 的回答很棒,所以我决定将其翻译为 Xamarin 以帮助更多人。

  1. 设置SearchView

在文件夹res/menu 中创建一个名为main.xml 的新文件。在其中添加一个项目并将actionViewClass 设置为android.support.v7.widget.SearchView。由于您使用的是支持库,因此您必须使用支持库的命名空间来设置 actionViewClass 属性。您的 xml 文件应如下所示:

 <?xml version="1.0" encoding="utf-8"?>
 <menu xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto">
     <item android:id="@+id/action_search"
           android:title="Search"
           android:icon="@android:drawable/ic_menu_search"
           app:showAsAction="always|collapseActionView"
           app:actionViewClass="android.support.v7.widget.SearchView" />
  </menu>

在您的Activity 中,您必须像往常一样扩充此菜单xml,然后您可以查找包含SearchViewMenuItem 并在QueryTextChange 上添加一个委托,我们将使用它来监听更改输入到SearchView 中的文本:

public override bool OnCreateOptionsMenu(IMenu menu)
    {
        MenuInflater.Inflate(Resource.Menu.main, menu);

        var item = menu.FindItem(Resource.Id.action_search);
        var searchView = MenuItemCompat.GetActionView(item);
        _searchView = searchView.JavaCast<Android.Support.V7.Widget.SearchView>();

        _searchView.QueryTextChange += (s, e) => _adapter.Filter.InvokeFilter(e.NewText);

        _searchView.QueryTextSubmit += (s, e) =>
        {
            // Handle enter/search button on keyboard here
            Toast.MakeText(this, "Searched for: " + e.Query, ToastLength.Short).Show();
            e.Handled = true;
        };

        MenuItemCompat.SetOnActionExpandListener(item, new SearchViewExpandListener(_adapter));

        return true;
    }

    private class SearchViewExpandListener : Java.Lang.Object, MenuItemCompat.IOnActionExpandListener
    {
        private readonly IFilterable _adapter;

        public SearchViewExpandListener(IFilterable adapter)
        {
            _adapter = adapter;
        }

        public bool OnMenuItemActionCollapse(IMenuItem item)
        {
            _adapter.Filter.InvokeFilter("");
            return true;
        }

        public bool OnMenuItemActionExpand(IMenuItem item)
        {
            return true;
        }
    }
  1. 设置Adapter

首先,添加一个将用于此示例的模型类:

public class Chemical
{
    public string Name { get; set; }

    public int DrawableId { get; set; }
}

这只是您的基本模型,它将在RecyclerView 中显示文本。这是显示布局的布局:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:padding="5dp">
    <ImageView
        android:id="@+id/chemImage"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_alignParentLeft="true"
        android:layout_margin="5dp" />
    <TextView
        android:id="@+id/chemName"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@+id/chemImage"
        android:layout_centerInParent="true"
        android:layout_marginLeft="5dp"
        android:layout_marginRight="5dp" />
 </RelativeLayout>

这是ChemicalHolder 类的ViewHolder

    public class ChemicalHolder : RecyclerView.ViewHolder
    {
        public ImageView Image { get; private set; }
        public TextView Caption { get; private set; }

        public ChemicalHolder(View itemView) : base(itemView)
        {
            Image = itemView.FindViewById<ImageView>(Resource.Id.chemImage);
            Caption = itemView.FindViewById<TextView>(Resource.Id.chemName);
        }
    }

3。 实现RecyclerView.Adapter

public class RecyclerViewAdapter : RecyclerView.Adapter, IFilterable
{
    private List<Chemical> _originalData;
    private List<Chemical> _items;
    private readonly Activity _context;

    public Filter Filter { get; private set; }

    public RecyclerViewAdapter(Activity activity, IEnumerable<Chemical> chemicals)
    {
        _items = chemicals.OrderBy(s => s.Name).ToList();
        _context = activity;

        Filter = new ChemicalFilter(this);
    }

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


    public override RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup parent, int viewType)
    {
        View itemView = LayoutInflater.From(parent.Context).Inflate(Resource.Layout.Chemical, parent, false);
        ChemicalHolder vh = new ChemicalHolder(itemView);
        return vh;
    }

    public override void OnBindViewHolder(RecyclerView.ViewHolder holder, int position)
    {
        ChemicalHolder vh = holder as ChemicalHolder;

        var chemical = _items[position];

        vh.Image.SetImageResource(chemical.DrawableId);
        vh.Caption.Text = chemical.Name;
    }

    public override int ItemCount
    {
        get { return _items.Count; }
    }

    public class ChemicalHolder{...

    private class ChemicalFilter{//Implement the Filter logic
 }
  1. 实现过滤逻辑

    private class ChemicalFilter : Filter
    {
        private readonly RecyclerViewAdapter _adapter;
        public ChemicalFilter(RecyclerViewAdapter adapter)
        {
            _adapter = adapter;
        }
    
        protected override FilterResults PerformFiltering(ICharSequence constraint)
        {
            var returnObj = new FilterResults();
            var results = new List<Chemical>();
            if (_adapter._originalData == null)
                _adapter._originalData = _adapter._items;
    
            if (constraint == null) return returnObj;
    
            if (_adapter._originalData != null && _adapter._originalData.Any())
            {
                // Compare constraint to all names lowercased. 
                // It they are contained they are added to results.
                results.AddRange(
                    _adapter._originalData.Where(
                        chemical => chemical.Name.ToLower().Contains(constraint.ToString())));
            }
    
            // Nasty piece of .NET to Java wrapping, be careful with this!
            returnObj.Values = FromArray(results.Select(r => r.ToJavaObject()).ToArray());
            returnObj.Count = results.Count;
    
            constraint.Dispose();
    
            return returnObj;
        }
    
        protected override void PublishResults(ICharSequence constraint, FilterResults results)
        {
            using (var values = results.Values)
                _adapter._items = values.ToArray<Java.Lang.Object>()
                    .Select(r => r.ToNetObject<Chemical>()).ToList();
    
            _adapter.NotifyDataSetChanged();
    
            // Don't do this and see GREF counts rising
            constraint.Dispose();
            results.Dispose();
        }
    }
    
  2. 用它来实现这个功能

        SetContentView(Resource.Layout.Main);
        SupportActionBar.SetDisplayShowHomeEnabled(true);
    
        var chemicals = new List<Chemical>
        {
            new Chemical {Name = "Niacin", DrawableId = Resource.Drawable.Icon},
            new Chemical {Name = "Biotin", DrawableId = Resource.Drawable.Icon},
            new Chemical {Name = "Chromichlorid", DrawableId = Resource.Drawable.Icon},
            new Chemical {Name = "Natriumselenit", DrawableId = Resource.Drawable.Icon},
            new Chemical {Name = "Manganosulfate", DrawableId = Resource.Drawable.Icon},
            new Chemical {Name = "Natriummolybdate", DrawableId = Resource.Drawable.Icon},
            new Chemical {Name = "Ergocalciferol", DrawableId = Resource.Drawable.Icon},
            new Chemical {Name = "Cyanocobalamin", DrawableId = Resource.Drawable.Icon},
        };
    
        _recyclerView = FindViewById<RecyclerView>(Resource.Id.recyclerView);
        _adapter = new RecyclerViewAdapter(this,chemicals);
        _LayoutManager = new LinearLayoutManager(this);
        _recyclerView.SetLayoutManager(_LayoutManager);
        _recyclerView.SetAdapter(_adapter);//
    

【讨论】:

  • 在这一行_searchView.QueryTextChange += (s, e) =&gt; _adapter.Filter.InvokeFilter(e.NewText); 从哪里调用_adapter
  • OnCreate方法中初始化_adapter_adapter = new RecyclerViewAdapter(this,chemicals)
  • 在这一行.Select(r =&gt; r.ToNetObject&lt;Chemical&gt;()).ToList();,我收到ToNetObject 的错误。我必须为此安装任何软件包吗?
  • 这是我尝试构建/Users/emmnock/Documents/Projects/peaceApp/Droid/Recycler/PeaceHeroHolder.cs(40,40): Error CS1061: 'Object' does not contain a definition for 'ToNetObject' and no extension method 'ToNetObject' accepting a first argument of type 'Object' could be found (are you missing a using directive or an assembly reference?) (CS1061) (App.Droid)时的错误参考
  • @Switz,请添加此类ObjectExtensions
猜你喜欢
  • 2020-04-28
  • 2017-11-11
  • 1970-01-01
  • 2021-12-03
  • 2018-08-23
  • 2017-04-06
  • 2018-11-28
  • 2017-01-24
  • 1970-01-01
相关资源
最近更新 更多