通过RecyclerView搜索 - Xamarin.Droid

时间:2017-07-09 16:16:21

标签: c# android xamarin xamarin.android

我一直在寻找Xamarin搜索recyclerView的方式。有谁可以请我参加一个关于如何以Xamarin方式做到这一点的演示?

1 个答案:

答案 0 :(得分:0)

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

有关详细信息,您可以阅读文档:Xamarin.Android中的Filtering ListView with SearchViewXaver Kapeller's answer关于使用RecyclerView过滤SearchView

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

  1. 设置SearchView
  2. 在文件夹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进行充气,然后您可以查找包含MenuItem的{​​{1}}并在SearchView上添加一个代理我们将用于监听对QueryTextChange

    中输入的文本的更改
    SearchView
    1. 设置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; } }
    2. 首先,添加将用于此示例的模型类:

      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> 类的ViewHolder

      ChemicalHolder

      3。 实施 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); } }

      RecyclerView.Adapter
      1. 实施过滤逻辑

        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
         }
        
      2. 使用它来实现此功能

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