您可以 使用Observable / Observer模式
来管理嵌套列表上的筛选器,这将从一个Observable父对象中更新每个嵌套列表。我解决了所有麻烦,现在可以很好地实现正确的行为。
因此,这是我要做的事情:
- 使用一个家长
SearchView
在Activity
- (可选)在嵌套列表中创建一个
Filter
类( android.widget.Filter )Adapter
- 然后,使用一个
Observable
/Observer
图案嵌套Fragment
与Activity
背景: 在尝试您的代码时,我遇到了三个问题:
- 我无法使用ActionBar进行搜索:
onQueryTextChange
似乎从未在Fragment
s中调用过。当我点击搜索图标时,在我看来,SearchView
(编辑文本,图标等)未附带搜索小部件(而是附加到活动的小部件)。 - 我无法运行自定义方法
filter2
:我的意思是,当我解决上一点时,该方法不起作用。确实,我必须使用通过Filter
和扩展其两种方法的自定义类:performFiltering
和publishResults
。没有它,当我在搜索栏中点击一个单词时,我将得到一个空白屏幕。但是,这可能只是我的代码,可能filter2()
对您来说效果很好… - 我无法在片段之间进行持久搜索:为每个子片段
SearchView
创建一个新片段。在我看来,您反复SearchView sv = new SearchView(...);
在嵌套片段中调用此行。因此,每次我切换到下一个片段时,展开的searchview都会删除其先前的文本值。
无论如何,经过一些研究,我在SO上找到了有关实现搜索片段的答案。除了您在父活动和片段中“复制”选项菜单代码外,几乎与您的代码相同。您不应该这样做-
我认为这是我先前提到的第一个问题的原因。
此外,答案链接中使用的模式(在一个片段中进行一次搜索)可能不适合您的模式(在一个片段中进行一次搜索)。您应在所有嵌套的父对象中调用一个。
SearchView``Activity``Fragment
解决方案: 这是我的管理方式:
#1使用父母SearchView
:
它将避免重复的功能,并让父级活动监督其所有子级。此外,这将避免菜单中出现重复图标。
这是主要的父
Activity类:
public class ActivityName extends AppCompatActivity implements SearchView.onQueryTextListener { @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_main, menu); MenuItem item = menu.findItem(R.id.action_search); SearchView searchview = new SearchView(this); SearchManager searchManager = (SearchManager) getSystemService(SEARCH_SERVICE); searchview.setSearchableInfo(searchManager.getSearchableInfo(getComponentName())); ... MenuItemCompat.setShowAsAction(item, MenuItemCompat.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW | MenuItemCompat.SHOW_AS_ACTION_IF_ROOM); MenuItemCompat.setActionView(item, searchview); searchview.setonQueryTextListener(this); searchview.setIconifiedByDefault(false); return super.onCreateOptionsMenu(menu); } private void changeSearchViewTextColor(View view) { ... } @Override public boolean onQueryTextSubmit(String query) { return false; } @Override public boolean onQueryTextChange(String newText) { // update the observer here (aka nested fragments) return true; }}#2(可选)创建Filter
小部件:
就像我之前说过的那样,我无法使其与一起使用
filter2(),因此我
Filter在网络上创建了一个示例作为任何示例。
很快,在嵌套片段的适配器中,如下所示:
private ArrayList<String> originalList; // I used String objects in my testsprivate ArrayList<String> filteredList;private ListFilter filter = new ListFilter();@Overridepublic int getCount() { return filteredList.size();}public Filter getFilter() { return filter;}private class ListFilter extends Filter { @Override protected FilterResults performFiltering(CharSequence constraint) { FilterResults results = new FilterResults(); if (constraint != null && constraint.length() > 0) { constraint = constraint.toString().toLowerCase(); final List<String> list = originalList; int count = list.size(); final ArrayList<String> nlist = new ArrayList<>(count); String filterableString; for (int i = 0; i < count; i++) { filterableString = list.get(i); if (filterableString.toLowerCase().contains(constraint)) { nlist.add(filterableString); } } results.values = nlist; results.count = nlist.size(); } else { synchronized(this) { results.values = originalList; results.count = originalList.size(); } } return results; } @SuppressWarnings("unchecked") @Override protected void publishResults(CharSequence constraint, FilterResults results) { if (results.count == 0) { notifyDataSetInvalidated(); return; } filteredList = (ArrayList<String>) results.values; notifyDataSetChanged(); }}#3使用Observable
/ Observer
模式:
活动(带有searchview)是
Observable对象,嵌套片段是
Observers(请参阅Observer模式)。基本上,当
onQueryTextChange将调用时,它将
update()在现有的观察者中触发该方法。
这是parent中的声明
Activity:
private static ActivityName instance;private FilterManager filterManager;@Overrideprotected void onCreate(Bundle savedInstanceState) { ... instance = this; filterManager = new FilterManager();}public static FilterManager getFilterManager() { return instance.filterManager; // return the observable class}@Overridepublic boolean onQueryTextChange(String newText) { filterManager.setQuery(newText); // update the observable value return true;}这是
Observable将侦听和“传递”更新的数据的类:
public class FilterManager extends Observable { private String query; public void setQuery(String query) { this.query = query; setChanged(); notifyObservers(); } public String getQuery() { return query; }}为了添加观察者片段以侦听searchview值,我在将它们初始化时进行了操作
FragmentStatePagerAdapter。
因此,在父片段中,我通过传递来创建内容选项卡
FilterManager:
private ViewPager pager;private ViewPagerAdapter pagerAdapter;@Overridepublic View onCreateView(...) { ... pagerAdapter = new ViewPagerAdapter( getActivity(), // pass the context, getChildFragmentManager(), // the fragment manager MainActivity.getFilterManager() // and the filter manager );}适配器会将观察者添加到父可观察对象,并在销毁子片段时将其删除。
这
ViewPagerAdapter是父片段的:
public class ViewPagerAdapter extends FragmentStatePagerAdapter { private Context context; private FilterManager filterManager; public ViewPagerAdapter(FragmentManager fm) { super(fm); } public ViewPagerAdapter(Context context, FragmentManager fm, FilterManager filterManager) { super(fm); this.context = context; this.filterManager = filterManager; } @Override public Fragment getItem(int i) { NestedFragment fragment = new NestedFragment(); // see (*) filterManager.addObserver(fragment); // add the observer return fragment; } @Override public int getCount() { return 10; } @Override public void destroyItem(ViewGroup container, int position, Object object) { NestedFragment fragment = (NestedFragment) object; // see (*) filterManager.deleteObserver(fragment); // remove the observer super.destroyItem(container, position, object); }}最后,使用
filterManager.setQuery()in调用inactivity时
onQueryTextChange(),这将在
update()实现的方法中的嵌套片段中接收
Observer。
这是带有
ListView要过滤的嵌套片段:
public class NestedFragment extends Fragment implements Observer { private boolean listUpdated = false; // init the update checking value ... // setup the listview and the list adapter ... // use onResume to filter the list if it's not already done @Override public void onResume() { super.onResume(); // get the filter value final String query = MainActivity.getFilterManager().getQuery(); if (listview != null && adapter != null&& query != null && !listUpdated) { // update the list with filter value listview.post(new Runnable() { @Override public void run() { listUpdated = true; // set the update checking value adapter.getFilter().filter(query); } }); } } ... // automatically triggered when setChanged() and notifyObservers() are called public void update(Observable obs, Object obj) { if (obs instanceof FilterManager) { String result = ((FilterManager) obs).getQuery(); // retrieve the search value if (listAdapter != null) { listUpdated = true; // set the update checking value listAdapter.getFilter().filter(result); // filter the list (with #2) } } }}#4。结论:
效果很好,所有嵌套片段中的列表仅通过一个searchview即可按预期进行更新。但是,在我上面的代码中有一个不便之处,您应注意:
- (请参见下面的改进)
我无法调用Fragment
常规对象并将其添加为观察者。实际上,我必须使用特定的片段类(在此处NestedFragment
)进行强制转换和初始化。可能有一个简单的解决方案,但我暂时找不到。
尽管如此,我还是得到了正确的行为,并且-我认为-
通过在活动中保持顶部的一个搜索小部件,这可能是一个很好的模式。因此,使用此解决方案,您可以获得正确的方向线索,以实现所需的目标。希望您会喜欢。
#5改进(编辑):
(请参阅*), 可以通过
Fragment
在所有嵌套片段上保留全局类扩展来添加观察者。这就是我将片段实例化到的方式ViewPager
:@Override
public Fragment getItem(int index) {
Fragment frag = null;
switch (index) {
case 0:
frag = new FirstNestedFragment();
break;
case 1:
frag = new SecondFragment();
break;
…
}
return frag;
}@Override
public Object instantiateItem(ViewGroup container, int position) {
ObserverFragment fragment =
(ObserverFragment) super.instantiateItem(container, position);
filterManager.addObserver(fragment); // add the observer
return fragment;
}@Override
public void destroyItem(ViewGroup container, int position, Object object) {
filterManager.deleteObserver((ObserverFragment) object); // delete the observer
super.destroyItem(container, position, object);
}
通过
ObserverFragment如下创建类:
public class ObserverFragment extends Fragment implements Observer { public void update(Observable obs, Object obj) { }}然后,通过扩展和覆盖
update()嵌套片段:
public class FirstNestedFragment extends ObserverFragment { @Override public void update(Observable obs, Object obj) { }}


