简体   繁体   中英

How can filter recyclerview in selected viewpager fragment on search?

I have 3 tab fragments in viewpager with tabs. All tabs have recyclerview with ListAdapter showing customers list. Each tab represents 1) all customers 2) New ordered customers 3) Paid customers. I want to set search filter only on tab selected fragment . If the Searchview can place on activity which is common for all fragments, will be better in my case. I tried several ways but was failed. My search was resulting always only in last tab (Paid). Please can any one help me with full example of code?

And my MainActivity

private void initializeTab(){

   mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());

   viewPager = (MyViewPager) findViewById(R.id.view_pager);
   viewPager.setOffscreenPageLimit(5);
   viewPager.setAdapter(mSectionsPagerAdapter);

   tabLayout = (SmartTabLayout) findViewById(R.id.tabs);
   tabLayout.setViewPager(viewPager);
   viewPager.setPagingEnabled(true);

}

private class SectionsPagerAdapter extends FragmentStatePagerAdapter {

  protected int currentPosition = -1;
  protected Fragment currentFragment;

  public SectionsPagerAdapter(FragmentManager fm) {
     super(fm,BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
  }

  @Override
  public Fragment getItem(int position) {

    return ViewPagerFragment.newInstance(getPageTitle(position)+"");
  }

  @Override
  public int getCount() {
    // Show 3 total pages.
    return 3;
  }

  @Override
  public CharSequence getPageTitle(int position) {
    switch (position) {
       case 0:
         return "All";
       case 1:
         return "New";
       case 2:
         return "Paid";
    }
       return null;
 }

 @Override
 public void setPrimaryItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
   super.setPrimaryItem(container, position, object);
   this.currentPosition = position;
   if (object instanceof Fragment){
      this.currentFragment = (Fragment)object;
   }
 }

 public Fragment getCurrentFragment() {
   return currentFragment;
 }

 public void setCurrentFragment(Fragment currentFragment) {
    this.currentFragment = currentFragment;
 }
}

and my Fragment

public class ViewPagerFragment extends AbstractFragment {
  ............
 public static ViewPagerFragment newInstance(String title) {
   ViewPagerFragment fragment = new ViewPagerFragment();
   Bundle args = new Bundle();
   args.putString("TITLE",title);
   fragment.setArguments(args);
   return fragment;
 }
 @Override
 public void onViewCreated(final View view, Bundle savedInstanceState) {
   swipeLayout = (SwipeRefreshLayout) view.findViewById(R.id.swipeToRefresh);

   recycler = (RecyclerView) view.findViewById(R.id.recycler);
   adapter = new CustomerAdapter(getContext());
   recycler.setLayoutManager(new LinearLayoutManager(getContext()));
   recycler.setHasFixedSize(true);
   recycler.addItemDecoration(new ItemDecoration(1,false, dpToPx(0),true,2));
   recycler.setItemAnimator(new DefaultItemAnimator());
   recycler.setAdapter(adapter);
   changeFragment(swipeLayout);
 }

 public void changeFragment(final SwipeRefreshLayout swipeLayout){

        final String tab = getArguments().getString("TITLE");

        loadDatas(allRecords,tab);

        swipeLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                swipeLayout.setRefreshing(true);
                utils.getDetails(getContext());
                utils.setOnDataLoaded(new MyUtils.DataLoadingListener() {
                    @Override
                    public void onDataLoaded(ArrayList<Customers> list) {
                        loadDatas(list, tab);
                        swipeLayout.setRefreshing(false);
                    }

                });

            }
        });


        // Scheme colors for animation
        swipeLayout.setColorSchemeColors(
                getResources().getColor(android.R.color.holo_blue_bright),
                getResources().getColor(android.R.color.holo_green_light),
                getResources().getColor(android.R.color.holo_orange_light),
                getResources().getColor(android.R.color.holo_red_light)
        );
  }

  void loadDatas(List<Customers> list, String tab){

        if (list != null && list.size() > 0) {
            List<Customers> tabList = new ArrayList<>();

            if (tab.equals("All")) {
                tabList = list;
            }else {
                for (Customers item : list) {
                    if (item.getStatus().equals(tab)) {
                        tabList.add(item);
                    }else {
                       Log.d(TAG, "loadDatas: "+item.getStatus());
                    }
                }
            }
            adapter.submitList(tabList);
        }
    }

}

About the recyclerview filter data:

  1. could make your class CustomerAdapter implements Filterable

like :

class Adapter extends RecyclerView.Adapter implements Filterable {
    ......    
    @Override
    public Filter getFilter() {
        return new Filter() {
            @Override
            protected FilterResults performFiltering(CharSequence constraint) {
                return ...;
            }

            @Override
            protected void publishResults(CharSequence constraint, FilterResults results) {

            }
        };
    }
}    
  1. could also refer this:https://github.com/xaverkapeller/Searchable-RecyclerView-Demo

About how to do this in selected viewpager fragment , you just need to invoke the search method of the current fragment.

the Searchview can place on activity which is common for all fragments, will be better in my case.

This is right.

I tried several ways but was failed. My search was resulting always only in last tab (Paid).

So, I'm assuming that the issue now isn't in the filtering itself, but that it always returns the results of the last tab; and therefore you probably didn't provide the filtering code for such a reason.

Now we've 3 tabs in the ViewPager , each represents a fragment; So we need to get the current selected fragment of the ViewPager in order to allow the activity send it the searched text.

To get the current fragment from ViewPager (Your case):

ViewPagerFragment currentFragment = (ViewPagerFragment) mViewPagerAdapter.instantiateItem(viewPager, viewPager.getCurrentItem());

To get the current fragment from ViewPager2:

The ViewPager has getCurrentItem() which returns the current page number So, we need to link the each page fragment to the page number.

But we can get a ViewPager fragment by its id (item id), so the first step is to have page Ids that equals to the corresponding position, to do so override getItemId in the ViewPager adapter.

@Override
public long getItemId(int position) {
    return position;
}

Then in the activity filtering part assuming you are searching for a String that is in a var named seachString :

int pageId = viewpager.getCurrentItem();

Fragment currentFragment = (ViewPagerFragment) getChildFragmentManager()
                                              .findFragmentByTag("f" + pageId);

Then after getting the current fragment, create some method in it that accepts a String parameter for the searched value:

So, in ViewPagerFragment , create:

public void searchFor(String search) {
    // filter the results of the RecyclerView
}

And call that method on the current fragment of the ViewPager in the activity:

currentFragment.searchFor(seachString);

At last I succeeded, I think it is not very professional but it is working fine. To help some one suffering I am sharing that here.

Firstly I added tabScrollingListener to get the selected fragment in MainActivity

public class MainActivity extends AppCompatActivity{

..........
  private ViewPagerFragment selectedFragment;

  private void initializeTab(){

    mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());

    viewPager = (MyViewPager) findViewById(R.id.view_pager);
    viewPager.setOffscreenPageLimit(5);
    viewPager.setAdapter(mSectionsPagerAdapter);

    tabLayout = (SmartTabLayout) findViewById(R.id.tabs);
    tabLayout.setViewPager(viewPager);
    viewPager.setPagingEnabled(true);
    viewPager.setCurrentItem(0);

    tabLayout.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
                selectedFragment = (ViewPagerFragment) mSectionsPagerAdapter.getCurrentFragment();
            }

            @Override
            public void onPageSelected(int position) {

            }

            @Override
            public void onPageScrollStateChanged(int state) {

            }
     });

  }

}

Then I transferred my filter function to Fragment like mentioned in Zain's answer . As I am using ListAdapter for my recycler it's easy to submit my filter list to adapter. I loaded my filter list on loadData function.

public class ViewPagerFragment extends AbstractFragment {
  ............
 private List<Customers> filterList;

 public static ViewPagerFragment newInstance(String title) {
   ViewPagerFragment fragment = new ViewPagerFragment();
   Bundle args = new Bundle();
   args.putString("TITLE",title);
   fragment.setArguments(args);
   return fragment;
 }
 @Override
 public void onViewCreated(final View view, Bundle savedInstanceState) {
   swipeLayout = (SwipeRefreshLayout) view.findViewById(R.id.swipeToRefresh);

   recycler = (RecyclerView) view.findViewById(R.id.recycler);
   adapter = new CustomerAdapter(getContext());
   recycler.setLayoutManager(new LinearLayoutManager(getContext()));
   recycler.setHasFixedSize(true);
   recycler.addItemDecoration(new ItemDecoration(1,false, dpToPx(0),true,2));
   recycler.setItemAnimator(new DefaultItemAnimator());
   recycler.setAdapter(adapter);
   changeFragment(swipeLayout);
 }

 public void changeFragment(final SwipeRefreshLayout swipeLayout){

        final String tab = getArguments().getString("TITLE");

        loadDatas(allRecords,tab);

        swipeLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                swipeLayout.setRefreshing(true);
                utils.getDetails(getContext());
                utils.setOnDataLoaded(new MyUtils.DataLoadingListener() {
                    @Override
                    public void onDataLoaded(ArrayList<Customers> list) {
                        loadDatas(list, tab);
                        swipeLayout.setRefreshing(false);
                    }

                });

            }
        });


        // Scheme colors for animation
        swipeLayout.setColorSchemeColors(
                getResources().getColor(android.R.color.holo_blue_bright),
                getResources().getColor(android.R.color.holo_green_light),
                getResources().getColor(android.R.color.holo_orange_light),
                getResources().getColor(android.R.color.holo_red_light)
        );
  }

  void loadDatas(List<Customers> list, String tab){

        if (list != null && list.size() > 0) {
            List<Customers> tabList = new ArrayList<>();

            if (tab.equals("All")) {
                tabList = list;
            }else {
                for (Customers item : list) {
                    if (item.getStatus().equals(tab)) {
                        tabList.add(item);
                    }else {
                       Log.d(TAG, "loadDatas: "+item.getStatus());
                    }
                }
            }
            filterList = tabList; // this fills filter list
            adapter.submitList(tabList);
        }
    }

}

public void filter(String text, String filter) {

        ArrayList<Customers> filteredlist = new ArrayList<>();

        // running a for loop to compare elements.
        if (filterList != null && filterList.size() > 0) {
            if (text.length() > 0) {
                for (Customers item : filterList) {
                   // here filter options gone
                }
            }else {
                filteredlist.addAll(filterList);
            }
        }
        adapter.submitList(filteredlist);

}

Yea, Now I got currentSelectedFragment with filter function in MainActivity In searchListener I can call it like selectedFragment.filter(query).

       searchview.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String query) {
                return false;
            }

            @Override
            public boolean onQueryTextChange(String newText) {

                selectedFragment.filter(newText); // search filter here

                return true;
            }
        });
Follow the below step to find the clicked tab, 

First add tab select listener 
    
    tabLayout.addOnTabSelectedListener(object:TabLayout.OnTabSelectedListener{
    override fun onTabSelected(tab: TabLayout.Tab?) {
       selectedFragment= fragmentViewPagerAdapter!!.fragments[tab!!.position]
    }
    override fun onTabUnselected(tab: TabLayout.Tab?) {
//               enter code here
            }
    override fun onTabReselected(tab: TabLayout.Tab?) {
//               enter code here
            }
        }) 

and then  setupWithViewPager 
        tabLayout.setupWithViewPager(viewPager)
  

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM