搜索查看没有在每个子TabLayout的标签过滤 [英] SearchView doesn't filter in each child Tab of TabLayout

查看:339
本文介绍了搜索查看没有在每个子TabLayout的标签过滤的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在这里,我有一个活动工具栏 包含一个搜索查看。而这一活动有多个片段。一个主要的片段出他们都有自己内部的10个片段。所有10个片段显示列表视图的数据。现在我想通过搜索查看 MainActivity 的过滤片段的所有名单。但它从来没有过滤每个片段的列表。现在我告诉你我是如何实现这一切。

MainActivity.java

 公共类MainActivity扩展AppCompatActivity {
 @覆盖
公共布尔onCreateOptionsMenu(菜单菜单){
    。getMenuInflater()膨胀(R.menu.menu_main,菜单);
    最终搜索查看搜索查看=(搜索查看)MenuItemCompat.getActionView(menu​​.findItem(R.id.action_search));
    SearchManager的SearchManager的=(SearchManager的)getSystemService(SEARCH_SERVICE);
    sea​​rchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
    changeSearchViewTextColor(搜索查看);
    返回true;
}
}

Fragment.java

 公共类CurrencyFragment2扩展android.support.v4.app.Fragment实现SearchView.OnQueryTextListener {    @覆盖
公共无效setMenuVisibility(布尔menuVisible){
    super.setMenuVisibility(menu​​Visible);
    如果(menu​​Visible&安培;&安培; getActivity()!= NULL){
        共享preferences preF = getActivity()获得preferences(0);
        INT ID = pref.getInt(viewpager_id,0);
        如果(ID == 2)
            setHasOptionsMenu(真);
 }
 }
    @覆盖
公共无效onCreateOptionsMenu(菜单菜单,MenuInflater气筒){
    inflater.inflate(R.menu.main,菜单); //删除不翻倍的菜单项
    菜单项项= menu.findItem(R.id.action_search);
    搜索查看SV =新搜索查看(((MainActivity)getActivity())getSupportActionBar()getThemedContext());
    changeSearchViewTextColor(SV);
    MenuItemCompat.setShowAsAction(项目,MenuItemCompat.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW | MenuItemCompat.SHOW_AS_ACTION_IF_ROOM);
    MenuItemCompat.setActionView(项目,SV);
    sv.setOnQueryTextListener(本);
    sv.setIconifiedByDefault(假);
    super.onCreateOptionsMenu(菜单,充气器);
}私人无效changeSearchViewTextColor(查看视图){
    如果(查看!= NULL){
        如果(查看的instanceof的TextView){
            ((的TextView)视图).setTextColor(Color.WHITE);
            ((的TextView)视图).setHintTextColor(Color.WHITE);
            ((的TextView)视图).setCursorVisible(真);
            返回;
        }否则如果(查看的instanceof的ViewGroup){
            ViewGroup中的ViewGroup =(ViewGroup中)视图。
            的for(int i = 0; I< viewGroup.getChildCount();我++){
                changeSearchViewTextColor(viewGroup.getChildAt(I));
            }
        }
    }
}@覆盖
公共布尔onQueryTextSubmit(查询字符串){
    返回true;
}@覆盖
公共布尔onQueryTextChange(字符串newText){
    如果(适配器!= NULL){
        adapter.filter2(newText);
    }
    返回true;
}

适配器类内部过滤器的方法。

  //过滤等级
公共无效过滤器2(字符串charText){
    charText = charText.toLowerCase(Locale.getDefault());
    items.clear();
    如果(charText.length()== 0){
        items.addAll(数组列表);
    }其他{
        对于(EquityDetails WP:数组列表){
            如果(wp.getExpert_title()。与toLowerCase(Locale.getDefault())。包含(charText)){
                items.add(WP);
            }
        }
    }
    notifyDataSetChanged();
}


解决方案

您可以通过用观察/ Observer模式,这从一个更新每个嵌套列表管理嵌套列表过滤器上的<一个HREF =htt​​ps://docs.oracle.com/javase/7/docs/api/java/util/Observable.html>观测父。我固定所有的烦恼以及它运作良好,现在要实现正确的行为。

因此​​,这里是我做了什么来实现它:


  1. 活动使用一个父搜索查看

  2. (可选)创建一个过滤器类( android.widget.Filter 的)嵌套的列表适配器

  3. 然后,使用观测 / 观察嵌套片段模式活动


背景::当我想你的code,我有三个问题:


  • 我做不到使用的动作条搜索: onQueryTextChange 似乎在片段 s内不会被调用。当我在搜索图标挖掘,这在我看来,搜索查看(EditText上,图标等),不与搜索部件连接(但连接到活动的部件)。

  • 我不能运行自定义方法过滤器2 :我的意思是,当我解决了previous点,这种方法是行不通的。事实上,我有自定义类由延长过滤器及其两个方法来发挥: performFiltering publishResults 。没有它,我得到了一个空白的画面时,我挖掘搜索栏的一句话。然而,这可能是我唯一的code,也许过滤器2()完全适用于你......

  • 我不能有片段之间的持久性搜索:每个孩子分片新创建搜索查看。在我看来,你反复调用此行搜索查看SV =新的搜索查看(...); 嵌套片段。所以我每次切换到下一个片段时,扩大搜索查看删除其previous文本值。

无论如何,一些研究之后,我发现这个答案对SO有关实现的Search片段。几乎是同一code是你的,除非你重复在父母的活动,并在片段选项菜单code。你不应该这样做 - 我认为这是我在previous点第一个问题的原因结果。
此外,在回答的链路(在一个片段一个搜索)中使用的图案可能不适合于你的(一个搜索多个片段)。你应该叫有一个搜索查看活动所有嵌套片段


解决方案:这是我怎么做的:

#1使用父搜索查看

这将避免重复功能,让家长监督活动的所有儿童。进一步说,这种将避免重复的图标菜单。结果
这是主父活动类:

 公共类ActivityName扩展AppCompatActivity实现SearchView.OnQueryTextListener {    @覆盖
    公共布尔onCreateOptionsMenu(菜单菜单){
        。getMenuInflater()膨胀(R.menu.menu_main,菜单);        菜单项项= menu.findItem(R.id.action_search);
        搜索查看搜索查看=新的搜索查看(本);
        SearchManager的SearchManager的=(SearchManager的)getSystemService(SEARCH_SERVICE);
        sea​​rchview.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
        ...
        MenuItemCompat.setShowAsAction(项目,
                MenuItemCompat.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW |
                MenuItemCompat.SHOW_AS_ACTION_IF_ROOM);
        MenuItemCompat.setActionView(项目,搜索查看);
        sea​​rchview.setOnQueryTextListener(本);
        sea​​rchview.setIconifiedByDefault(假);        返回super.onCreateOptionsMenu(菜单);
    }    私人无效changeSearchViewTextColor(查看视图){...}    @覆盖
    公共布尔onQueryTextSubmit(查询字符串){返回false; }    @覆盖
    公共布尔onQueryTextChange(字符串newText){
        //在这里更新观察员(又名嵌套片段)
        返回true;
    }
}

#2(可选)创建一个过滤器部件:

就像我说的previously,我不能让它与过滤器2()工作,所以我创建了一个过滤器类在网络上的任何例子。结果
它很快样子,在嵌套片段的适配器,如下所示:

 私人的ArrayList&LT;串GT; originalList; //我用String对象在我的测试
私人的ArrayList&LT;串GT; filteredList;
私人ListFilter过滤器=新ListFilter();@覆盖
公众诠释的getCount(){
    返回filteredList.size();
}公共过滤用getFilter(){
    返回过滤器;
}私有类ListFilter扩展过滤器{
    @覆盖
    保护FilterResults performFiltering(CharSequence的约束){
        FilterResults结果=新FilterResults();
        如果(约束=空&放大器;!&放大器; constraint.length()大于0){
            约束= constraint.toString()与toLowerCase()。
            最终名单&LT;串GT;名单= originalList;
            诠释计数=则为list.size();            最终的ArrayList&LT;串GT; NLIST =新的ArrayList&LT;&GT;(计数);
            串filterableString;
            的for(int i = 0; I&LT;计数;我++){
                filterableString = list.get(ⅰ);
                如果(filterableString.toLowerCase()。包括(约束)){
                    nlist.add(filterableString);
                }
            }            results.values​​ = NLIST;
            results.count = nlist.size();
        }其他{
            同步(本){
                results.values​​ = originalList;
                results.count = originalList.size();
            }
        }
        返回结果;
    }    @燮pressWarnings(未登记)
    @覆盖
    保护无效publishResults(CharSequence的约束,FilterResults结果){
        如果(results.count == 0){
            notifyDataSetInvalidated();
            返回;
        }        filteredList =(ArrayList的&LT;串GT;)results.values​​;
        notifyDataSetChanged();
    }
}

#3使用观测 / 观察模式:

活动 - 与搜索查看 - 是观测对象和嵌套的片段是观察 S(< A HREF =htt​​p://www.javaworld.com/article/2077258/learn-java/observer-and-observable.html>看到Observer模式)。基本上,当 onQueryTextChange 将被调用,它会触发 update()方法在existant观察家方法。

下面是父声明活动

 私有静态ActivityName实例;
私人FilterManager filterManager;@覆盖
保护无效的onCreate(捆绑savedInstanceState){
    ...
    例如=这一点;
    filterManager =新FilterManager();
}公共静态FilterManager getFilterManager(){
    返回instance.filterManager; //返回观察到的类
}@覆盖
公共布尔onQueryTextChange(字符串newText){
    filterManager.setQuery(newText); //更新可观察value
    返回true;
}

这是观测类,将听取和通过更新后的数据:

 公共类FilterManager扩展观测{
    私人字符串查询;    公共无效setQuery(查询字符串){
        this.query =查询;
        setChanged();
        notifyObservers();
    }    公共字符串getQuery(){
        返回查询;
    }
}

为了增加观察者片段试听搜索查看值,我这样做,当他们在被初始化的 FragmentStatePagerAdapter 。结果
所以在父母的片段,我通过传递创建的内容选项卡中的 FilterManager

 私人ViewPager寻呼机;
私人ViewPagerAdapter pagerAdapter;@覆盖
公共查看onCreateView(...){
    ...
    pagerAdapter =新ViewPagerAdapter(
         getActivity(),//传递的范围内,
         getChildFragmentManager()//片段经理
         MainActivity.getFilterManager()//和过滤管理器
    );
}

适配器将添加观察者父观察到并删除它,当孩子的片段被销毁。结果
这里的 ViewPagerAdapter 父片段:

 公共类ViewPagerAdapter扩展FragmentStatePagerAdapter {    私人上下文的背景下;
    私人FilterManager filterManager;    公共ViewPagerAdapter(FragmentManager FM){
        超(FM);
    }    公共ViewPagerAdapter(上下文的背景下,FragmentManager FM,
               FilterManager filterManager){
        超(FM);
        this.context =背景;
        this.filterManager = filterManager;
    }    @覆盖
    公共片段的getItem(int i)以{
        NestedFragment片段=新NestedFragment(); //见(*)
        filterManager.addObserver(片段); //添加观察者
        返回片段;
    }    @覆盖
    公众诠释的getCount(){
        返回10;
    }    @覆盖
    公共无效destroyItem(ViewGroup中的容器,INT位置,Object对象){
        NestedFragment片段=(NestedFragment)对象; //见(*)
        filterManager.deleteObserver(片段); //删除观察者
        super.destroyItem(集装箱,位置,对象);
    }
}

最后,当 filterManager.setQuery()活动正在调用 onQueryTextChange(),这将被接收在 update()方法正在实施观察 方法嵌套片段。结果
这是的 ListView控件过滤嵌套的片段:

 公共类NestedFragment扩展片段实现观测{
    私人布尔listUpdated = FALSE; //初始化的更新检查值
    ...
    //设置列表视图和列表适配器
    ...
    //使用onResume过滤列表,如果它没有这样做
    @覆盖
    公共无效onResume(){
        super.onResume();
        //获取筛选值
        最终的查询字符串= MainActivity.getFilterManager()getQuery()。
        如果(列表视图= NULL&放大器;!&安培;!适配器= NULL
                     &功放;&安培;查询= NULL&放大器;!&安培; !listUpdated){
            //更新过滤器值列表
            listview.post(新的Runnable(){
                @覆盖
                公共无效的run(){
                    listUpdated = TRUE; //设置更新检查值
                    。adapter.getFilter()过滤器(查询);
                }
            });
        }
    }
    ...
    setChanged //时自动触发()和notifyObservers()被称为
    公共无效更新(可观察OBS,obj对象){
        如果(OBS的instanceof FilterManager){
            字符串结果=((FilterManager)OBS).getQuery(); //检索搜索值
            如果(listAdapter!= NULL){
                listUpdated = TRUE; //设置更新检查值
                。listAdapter.getFilter()过滤器(结果); //过滤列表(#2)
            }
        }
    }
}

#4结论:

这个效果很好,在所有嵌套的片段列表是只用一个搜索查看更新预期。但是,在我上面code的incovenient,你应该知道的:


  • (见下面的改进)的<击>我不能叫片段总体目标,并把它添加到被观察者。事实上,我已经投与特定的片段类的init(这里 NestedFragment );有可能是一个简单的解决方案,但我没有找到它了。

尽管这样,我得到正确的行为 - 我认为 - 这可能是通过保持一个搜索插件在顶部,在活动的良好格局。因此,与此解决方案,你可以得到一个线索,一个正确的方向,实现你想要什么。我希望你会喜欢。


#5改进(编辑):


  • (见*)您可以通过保持一个全球性的片段类扩展上的所有嵌套片段添加观察员。这怎么我实例化我的片段到 ViewPager

      @覆盖
    公共片段的getItem(INT指数){
        片段FRAG = NULL;
        开关(指数){
            情况下0:
                FRAG =新FirstNestedFragment();
                打破;
            情况1:
                FRAG =新SecondFragment();
                打破;
            ...
        }
        返回FRAG;
    }@覆盖
    公共对象instantiateItem(ViewGroup中的容器,INT位置){
        ObserverFragment片段=
                (ObserverFragment)super.instantiateItem(集装箱,位置);
        filterManager.addObserver(片段); //添加观察者
        返回片段;
    }@覆盖
    公共无效destroyItem(ViewGroup中的容器,INT位置,Object对象){
        filterManager.deleteObserver((ObserverFragment)对象); //删除观察者
        super.destroyItem(集装箱,位置,对象);
    }

    通过创建 ObserverFragment 类,如下所示:

     公共类ObserverFragment扩展片段实现观测{
        公共无效更新(可观察OBS,obj对象){/ *什么也不做此* /}
    }

    然后,通过延伸和覆盖在嵌套片段的update()

     公共类FirstNestedFragment扩展ObserverFragment {
        @覆盖
        公共无效更新(可观察OBS,obj对象){}
    }


Here, I have a toolbar in an Activity which contains a SearchView. And that activity has multiple fragments. One main fragment out of them have 10 more fragments inside itself. All 10 fragments are showing data in listviews. Now I'm trying to filter all the lists of fragments by SearchView of MainActivity. But it never filters list of each fragment. Now I show you how I implemented it all.

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

Filter method inside Adapter class.

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

解决方案

You can manage the filter on nested list by using an Observable/Observer pattern, this will update each nested list from one Observable parent. I fixed all troubles and it works well now to achieve the right behaviour.

Therefore, here's what I did to achieve it:

  1. Using one parent SearchView in Activity
  2. (optional) Create a Filter class (android.widget.Filter) in nested list Adapter
  3. Then, using an Observable/Observer pattern for nested Fragment with Activity


Background: When I tried your code, I had three problems:

  • I cannot do a search using the ActionBar: onQueryTextChange seems to be never called in Fragments. When I tap on search icon, it seems to me that SearchView (edittext, icon, etc) is not attached with the search widget (but attached to the activity's widget).
  • I cannot run the custom method filter2: I mean, when I resolved the previous point, this method doesn't work. Indeed, I have to play with custom class extending by Filter and its two methods: performFiltering and publishResults. Without it, I got a blank screen when I tap a word in search bar. However, this could be only my code and maybe filter2() works perfectly for you...
  • I cannot have a persistent search between fragments: for each child fragment a new SearchView is created. It seems to me that you repeatedly call this line SearchView sv = new SearchView(...); in nested fragment. So each time I switch to the next fragment, the expanded searchview removes its previous text value.

Anyway, after some researches, I found this answer on SO about implementing a Search fragment. Almost the same code as yours, except that you "duplicate" the options menu code in parent activity and in fragments. You shouldn't do it - I think it's the cause of my first problem in previous points.
Besides, the pattern used in the answer's link (one search in one fragment) might not be adapted to yours (one search for multiple fragments). You should call one SearchView in the parent Activity for all nested Fragment.


Solution: This is how I managed it:

#1 Using a parent SearchView:

It will avoid duplicate functions and let the parent activity supervise all its children. Futhermore, this will avoid your duplication icon in the menu.
This is the main parent Activity class:

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 (optional) Create a Filter widget:

Like I said previously, I cannot get it work with filter2(), so I create a Filter class as any example on the web.
It quickly looks like, in the adapter of nested fragment, as follows:

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 Using an Observable/Observer pattern:

The activity - with the searchview - is the Observable object and the nested fragments are the Observers (see Observer pattern). Basically, when the onQueryTextChange will be called, it will trigger the update() method in the existant observers.
Here's the declaration in 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;
}

This is the Observable class which will listen and "pass" the updated data:

public class FilterManager extends Observable {
    private String query;

    public void setQuery(String query) {
        this.query = query;
        setChanged();
        notifyObservers();
    }

    public String getQuery() {
        return query;
    }
}

In order to add the observer fragments to listen the searchview value, I do it when they are initialized in the FragmentStatePagerAdapter.
So in the parent fragment, I create the content tabs by passing the 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
    );
}

The adapter will add the observer to the parent observable and remove it when the child fragments are destroyed.
Here's the ViewPagerAdapter of parent fragment:

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

Finally, when filterManager.setQuery() in activity is called with onQueryTextChange(), this will be received in nested fragment in update() method which are implementing Observer.
This is the nested fragments with the ListView to filter:

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 Conclusion:

This works well, the lists in all nested fragments are updated as expected by just one searchview. However, there is an incovenient in my above code that you should be aware of:

  • (see improvements below) I cannot call Fragment general object and add it to being an observer. Indeed, I have to cast and init with the specific fragment class (here NestedFragment); there might be a simple solution, but I didn't find it for now.

Despite this, I get the right behaviour and - I think - it might be a good pattern by keeping one search widget at the top, in activity. So with this solution, you could get a clue, a right direction, to achieve what you want. I hope you'll enjoy.


#5 Improvements (edit):

  • (see *) You can add the observers by keeping a global Fragment class extension on all nested fragments. This how I instantiate my fragments to the 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);
    }
    

    By creating the ObserverFragment class as follows:

    public class ObserverFragment extends Fragment implements Observer {
        public void update(Observable obs, Object obj) { /* do nothing here */ }
    }
    

    And then, by extending and overriding update() in the nested fragments:

    public class FirstNestedFragment extends ObserverFragment {
        @Override
        public void update(Observable obs, Object obj) { }
    }    
    

这篇关于搜索查看没有在每个子TabLayout的标签过滤的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆