我无法通过recylerview
操作栏过滤searchview
中的数据。我有一个项目示例并尝试实现该方法。但数据不会过滤。
我把它放在我的片段上(搜索视图)
public override void OnCreateOptionsMenu(IMenu menu,MenuInflater menuInflater)
{
//SearchMenu
menuInflater.Inflate(Resource.Menu.nav_search, menu);
var searchItem = menu.FindItem(Resource.Id.action_search);
var provider = MenuItemCompat.GetActionView(searchItem);
mSearchView = provider.JavaCast<Android.Support.V7.Widget.SearchView>();
mSearchView.QueryTextChange += (s, e) => mLocationsAdapter.Filter.InvokeFilter(e.NewText);
mSearchView.QueryTextSubmit += (s, e) =>
{
Toast.MakeText(this.Activity, "You searched: " + e.Query, ToastLength.Short).Show();
e.Handled = true;
};
MenuItemCompat.SetOnActionExpandListener(searchItem, new SearchViewExpandListener(mLocationsAdapter));
}
这是我的适配器:
namespace ShopDiaryApp.Adapter
{
public class LocationsRecycleAdapter : RecyclerView.Adapter,IFilterable
{
private readonly Activity mActivity;
private List<LocationViewModel> mLocations;
private List<LocationViewModel> mFilteredLocations;
private int mSelectedPosition = -1;
public LocationsRecycleAdapter(List<LocationViewModel> locations, Activity activity)
{
this.mLocations = locations;
this.mActivity = activity;
Filter = new LocationFilter(this);
}
public override int ItemCount => this.mLocations.Count;
public Filter Filter { get; private set; }
public event EventHandler<int> ItemClick;
private void OnClick(int position)
{
this.ItemClick?.Invoke(this, position);
NotifyItemChanged(position);
mSelectedPosition = position;
NotifyItemChanged(position);
}
public override void OnBindViewHolder(RecyclerView.ViewHolder holder, int position)
{
if (this.mLocations.Count > 0)
{
var vh = holder as ViewHolder;
if (vh != null)
{
var location = this.mLocations[position];
vh.LocationName.Text = location.Name;
vh.LocationAddress.Text = location.Address;
vh.LocationDescription.Text = location.Description;
vh.ItemView.Selected = (mSelectedPosition == position);
}
}
}
public override RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup parent, int viewType)
{
var v = LayoutInflater.From(parent.Context).Inflate(Resource.Layout.AdapterLocations, parent, false);
var vh = new ViewHolder(v, this.OnClick);
return vh;
}
public class ViewHolder : RecyclerView.ViewHolder
{
public ViewHolder(IntPtr javaReference, JniHandleOwnership transfer)
: base(javaReference, transfer)
{
}
public ViewHolder(View itemView, Action<int> listener)
: base(itemView)
{
this.LocationName = itemView.FindViewById<TextView>(Resource.Id.textviewLocationsAdapterName);
this.LocationAddress = itemView.FindViewById<TextView>(Resource.Id.textviewLocationAdapterAddress);
this.LocationDescription = itemView.FindViewById<TextView>(Resource.Id.textviewLocationAdapterDescription);
itemView.Click += (sender, e) => listener(this.LayoutPosition);
}
public TextView LocationName { get; }
public TextView LocationAddress { get; }
public TextView LocationDescription { get; }
}
private class LocationFilter : Filter
{
private readonly LocationsRecycleAdapter mLocationAdapter;
public LocationFilter(LocationsRecycleAdapter adapter)
{
mLocationAdapter = adapter;
}
protected override FilterResults PerformFiltering(ICharSequence constraint)
{
var returnObj = new FilterResults();
var results = new List<LocationViewModel>();
if (mLocationAdapter.mLocations == null)
mLocationAdapter.mLocations = mLocationAdapter.mFilteredLocations;
if (constraint == null) return returnObj;
if (mLocationAdapter.mLocations != null && mLocationAdapter.mLocations.Any())
{
// Compare constraint to all names lowercased.
// It they are contained they are added to results.
results.AddRange(
mLocationAdapter.mLocations.Where(
location => location.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)
mLocationAdapter.mFilteredLocations = values.ToArray<Java.Lang.Object>()
.Select(r => r.ToNetObject<LocationViewModel>()).ToList();
mLocationAdapter.NotifyDataSetChanged();
// Don't do this and see GREF counts rising
//constraint.Dispose();
//results.Dispose();
}
}
}
}
在qazxsw poi中,我得到了过滤后的数据。但Recyclerview不会更新(未过滤)。我错过了什么?感谢帮助 :)
我认为你应该在protected override void PublishResults(ICharSequence constraint, FilterResults results)
中使用mFilteredLocations
:
OnBindViewHolder
因此,您的if (this.mFilteredLocations.Count > 0)
...
var location = this.mFilteredLocations[position];
保留为您的原始位置列表以及您在mLocations
上显示的内容始终是您的过滤列表。显然,在开始时,RecyclerView
和mFilteredLocations
必须具有相同的项目。
mLocations
在您的过滤器上,您正在更改public LocationsRecycleAdapter(List<LocationViewModel> locations, Activity activity)
{
this.mLocations = locations;
this.mFilteredLocations = locations;
this.mActivity = activity;
Filter = new LocationFilter(this);
}
并通知已更改的数据集,以便刷新所有数据。但是只有在进行上述更改后才会生效。
mFilteredLocations
你有另一个相关的问题/答案,但在Android上它可以作为进一步的指导。
HIH