在这里,我有一个toolbar
在Activity
其中包含SearchView
。该活动具有多个片段。其中一个主要片段本身内部还有10个片段。所有10个片段都在列表视图中显示数据。现在,我试图通过筛选片段的所有列表SearchView
中MainActivity
。但是它永远不会过滤每个片段的列表。现在,我向您展示如何实现这一切。
MainActivity.java
public class MainActivity extends AppCompatActivity {
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
final SearchView searchView = (SearchView) MenuItemCompat.getActionView(menu.findItem(R.id.action_search));
SearchManager searchManager = (SearchManager) getSystemService(SEARCH_SERVICE);
searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
changeSearchViewTextColor(searchView);
return true;
}
}
Fragment.java
public class CurrencyFragment2 extends android.support.v4.app.Fragment implements SearchView.OnQueryTextListener {
@Override
public void setMenuVisibility(boolean menuVisible) {
super.setMenuVisibility(menuVisible);
if (menuVisible && getActivity() != null) {
SharedPreferences pref = getActivity().getPreferences(0);
int id = pref.getInt("viewpager_id", 0);
if (id == 2)
setHasOptionsMenu(true);
}
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.main, menu); // removed to not double the menu items
MenuItem item = menu.findItem(R.id.action_search);
SearchView sv = new SearchView(((MainActivity) getActivity()).getSupportActionBar().getThemedContext());
changeSearchViewTextColor(sv);
MenuItemCompat.setShowAsAction(item, MenuItemCompat.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW | MenuItemCompat.SHOW_AS_ACTION_IF_ROOM);
MenuItemCompat.setActionView(item, sv);
sv.setOnQueryTextListener(this);
sv.setIconifiedByDefault(false);
super.onCreateOptionsMenu(menu, inflater);
}
private void changeSearchViewTextColor(View view) {
if (view != null) {
if (view instanceof TextView) {
((TextView) view).setTextColor(Color.WHITE);
((TextView) view).setHintTextColor(Color.WHITE);
((TextView) view).setCursorVisible(true);
return;
} else if (view instanceof ViewGroup) {
ViewGroup viewGroup = (ViewGroup) view;
for (int i = 0; i < viewGroup.getChildCount(); i++) {
changeSearchViewTextColor(viewGroup.getChildAt(i));
}
}
}
}
@Override
public boolean onQueryTextSubmit(String query) {
return true;
}
@Override
public boolean onQueryTextChange(String newText) {
if (adapter != null) {
adapter.filter2(newText);
}
return true;
}
Adapter类中的Filter方法。
// Filter Class
public void filter2(String charText) {
charText = charText.toLowerCase(Locale.getDefault());
items.clear();
if (charText.length() == 0) {
items.addAll(arraylist);
} else {
for (EquityDetails wp : arraylist) {
if (wp.getExpert_title().toLowerCase(Locale.getDefault()).contains(charText)) {
items.add(wp);
}
}
}
notifyDataSetChanged();
}
您可以 使用Observable / Observer模式
来管理嵌套列表上的筛选器,这将从一个Observable父对象中更新每个嵌套列表。我解决了所有麻烦,现在可以很好地实现正确的行为。
因此,这是我要做的事情:
SearchView
在Activity
Filter
类( android.widget.Filter )Adapter
Observable
/ Observer
图案嵌套Fragment
与Activity
背景: 在尝试您的代码时,我遇到了三个问题:
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 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使用Observable
/ Observer
模式:
活动(带有searchview)是Observable
对象,嵌套片段是Observer
s(请参阅Observer模式)。基本上,当onQueryTextChange
将调用时,它将update()
在现有的观察者中触发该方法。
这是parent中的声明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;
}
}
为了添加观察者片段以侦听searchview值,我在将它们初始化时进行了操作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);
}
}
最后,使用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) { /* do nothing here */ }
}
然后,通过扩展和覆盖update()
嵌套片段:
public class FirstNestedFragment extends ObserverFragment {
@Override
public void update(Observable obs, Object obj) { }
}
搜索视图显示在每个列表视图行:检查附加的scrrenshot。 我怎样才能让它只在顶端出现一次呢。 在此输入图像描述
问题内容: 我有一个带有自定义标签的组件。该组件包含(显示标签标题)和(关闭按钮)。当我在停止接收鼠标事件的站点中更改文本时,如果直接单击标签,则无法再选择该选项卡,而如果单击标签周围,则可以选择该选项卡。有任何想法吗? 一段代码: 问题答案: 问题与我进行更多挖掘之后在此处发布的问题有关:setToolTipText消耗鼠标事件的解决方法?
当我运行这段代码时,两个不同片段中的toast显示在一个选项卡上。当我滑动到下一个选项卡时,什么也不显示。 这是我的主要选项卡活动: 这是适配器类: 这是我的第一个片段: 如有任何建议,我们将不胜感激。我被困在这了。
我一直在尝试在工作中实现Autosys作业计划的树表示。由于每个作业(流程)可以有一个或多个依赖作业,因此我决定使用n元树实现,以便映射流程。我使用java集合来实现同样的目标。 Q1(已解决):目前的问题是显示功能被挂在一个无限循环中。我尝试寻找现有的线程,但无法遇到使用迭代器进行遍历的示例。 Q2:(打开)显示功能以后序方式遍历树。我希望以一种级别顺序的方式遍历它,其中节点以级别为基础进行打印
我正在尝试隐藏ActionBar中的子菜单和SearchView。我在用ActionBarsherlock。 我想通过点击按钮隐藏子菜单和SearchView