您可以使用可观察/观察者模式管理嵌套列表上的筛选器,这将更新来自一个可观察父级的每个嵌套列表。我解决了所有问题,现在工作得很好,以实现正确的行为。
因此,以下是我为实现它所做的:
- 在 中使用一个父项
SearchView
Activity
- (可选)在嵌套列表中创建一个类(android.widget.Filter)
Filter
Adapter
- 然后,使用 / 模式嵌套
Observable
Observer
Fragment
Activity
背景:当我尝试你的代码时,我有三个问题:
- 我无法使用ActionBar进行搜索:似乎从未在s中调用过。当我点击搜索图标时,在我看来(编辑文本,图标等)没有与搜索小部件一起附加(而是附加到活动的小部件)。
onQueryTextChange
Fragment
SearchView
- 我无法运行自定义方法:我的意思是,当我解决上一点时,此方法不起作用。实际上,我必须使用自定义类扩展及其两种方法:和。没有它,当我在搜索栏中点击一个单词时,我得到了一个空白屏幕。但是,这可能只是我的代码,也许非常适合您...
filter2
Filter
performFiltering
publishResults
filter2()
- 我无法在片段之间进行持久搜索:为每个子片段创建一个新片段。在我看来,您反复在嵌套片段中调用此行。因此,每次我切换到下一个片段时,扩展的搜索视图都会删除其以前的文本值。
SearchView
SearchView sv = new SearchView(...);
无论如何,经过一些研究,我在SO上找到了关于实现搜索片段的答案。几乎与您的代码相同,只是您在父活动和片段中“复制”了选项菜单代码。你不应该这样做 - 我认为这是我在前几点中的第一个问题的原因。
此外,答案链接中使用的模式(一个片段中的一个搜索)可能不适合您的模式(一个搜索多个片段)。您应该在父级中为所有嵌套的 调用一个。SearchView
Activity
Fragment
溶液:这就是我管理它的方式:
#1 使用父搜索视图
:
它将避免重复的功能,并让父活动监督其所有子活动。此外,这将避免菜单中的重复图标。
这是主要的父类: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(可选)创建过滤器
微件:
就像我之前说的,我无法使用它,所以我创建了一个类作为网络上的任何示例。
在嵌套片段的适配器中,它很快看起来像这样:filter2()
Filter
private ArrayList<String> originalList; // I used String objects in my tests
private ArrayList<String> filteredList;
private ListFilter filter = new ListFilter();
@Override
public 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 使用可观察
/观察者
模式:
活动 ( 使用搜索视图 - 是对象,嵌套片段是 s(请参见观察者模式)。基本上,当调用时,它将在现有的观察者中触发该方法。
下面是父级中的声明:Observable
Observer
onQueryTextChange
update()
Activity
private static ActivityName instance;
private FilterManager filterManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
...
instance = this;
filterManager = new FilterManager();
}
public static FilterManager getFilterManager() {
return instance.filterManager; // return the observable class
}
@Override
public 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;
}
}
为了添加观察者片段来侦听搜索视图值,我在 .
因此,在父片段中,我通过传递以下内容来创建内容选项卡:FragmentStatePagerAdapter
FilterManager
private ViewPager pager;
private ViewPagerAdapter pagerAdapter;
@Override
public 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);
}
}
最后,当在活动中调用时,这将在正在实现的方法中的嵌套片段中接收。
这是具有 to 筛选器的嵌套片段:filterManager.setQuery()
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 结论:
这很有效,所有嵌套片段中的列表都按预期仅由一个搜索视图更新。但是,在我的上述代码中有一个不方便的地方,您应该注意:
-
(请参阅下面的改进)
我无法将 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) { /* do nothing here */ }
}
然后,通过在嵌套片段中扩展和覆盖:update()
public class FirstNestedFragment extends ObserverFragment {
@Override
public void update(Observable obs, Object obj) { }
}