4

I have two tabs and each tabs has its own searchbar.

I bind the searchbar in onCreateOptionsMenu. However, the searchbars only work if I leave the screen once and return to the screen (meaning it needs one more lifecycle for the searchbars to react). I confirmed that onCreateOptionsMenu is indeed called two times at the time of the creation of the ViewPagerFragment.

I bind them like this:

MenuItem searchItem = menu.findItem(R.id.search);
searchItem.setVisible(true);

SearchView searchView = (SearchView) searchItem.getActionView();
searchView.setImeOptions(EditorInfo.IME_ACTION_DONE);

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

     @Override
     public boolean onQueryTextChange(String newText) {
           ...
          return false;
     }
});

I am guessing this bug is related to the tabs. How do implement a working searchbar with tabs (i.e. viewpager2)?


I call this on onCreateOptionsMenu:

public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
    super.onCreateOptionsMenu(menu, inflater);
    // Call the above...
}

The ViewPager hosting them looks like this:

private void init(View view) {
    ViewPager2 viewPager2 = view.findViewById(R.id.view_pager_fragment_view_pager);
    TabLayout tabLayout = view.findViewById(R.id.tab_layout_fragment_view_pager);
    viewPager2.setUserInputEnabled(true);

    viewPager2.setAdapter(new ViewPagerFragmentAdapter(ViewPagerFragment.this));
    viewPager2.setOffscreenPageLimit(5);

    new TabLayoutMediator
            (tabLayout, viewPager2,
                    (tab, position) -> tab.setText(titles[position])).attach();
}
Josip Domazet
  • 2,246
  • 2
  • 14
  • 37
  • Sounds like your issue come from your `searchView` have you done some research in this way ? – Biscuit Mar 02 '20 at 13:51
  • It seems the issue is related to both the fragments calling (creating) the menu. In this case, you should use the activity to inflate the menu and bind the search bar and based on the current page (fragment), dispatch the events to that fragment. – Froyo Mar 02 '20 at 15:55
  • I do not think I can do that, I am calling all previous method in onCreateOptionsMenu in each Fragment - see my updated question. – Josip Domazet Mar 02 '20 at 20:59
  • @Froyo I added more information in my post. – Josip Domazet Mar 03 '20 at 17:02
  • Maybe you should move this part of code to onPrepareOptionsMenu method and call activity's invalidateOptionsMenu() method when viewPager page changes? – Bakhtiyor Begmatov Mar 05 '20 at 12:47
  • @BakhtiyorBegmatov That doesnt change it either. I still need to switch to the other fragment and back for it work. I think the binding that I do in onCreateOptionsMenu or onPrepareOptionsMenu gets somehow overriden (maybe by the hosting fragment) ? – Josip Domazet Mar 05 '20 at 17:51

1 Answers1

2

OP and I were communicating while we found a solution.

First each fragment was changed to

public class MergedItemsFragment extends Fragment implements SearchView.OnQueryTextListener {

    /// ------------------------------
    /// SearchView.OnQueryTextListener

    @Override
    public boolean onQueryTextSubmit(String query) {
        // ...
        return false;

    }

    @Override
    public boolean onQueryTextChange(String newText) {
        // ...
        return false;

    }

    /// --------
    /// Fragment

    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {

        return inflater.inflate(R.layout.fragment_merged_items, container, false);

    }

    @Override
    public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
        super.onCreateOptionsMenu(menu, inflater);

        final MenuItem   searchItem = menu.findItem(R.id.search);
        final SearchView searchView = (SearchView) searchItem.getActionView();

        searchView.setImeOptions(EditorInfo.IME_ACTION_DONE);
        searchView.setOnQueryTextListener(this);

    }

}

  • SearchView was inflated by using a menu.xml file within the App's Activity.
  • SearchView.OnQueryTextListener was implemented by each Fragment that needed access to the SearchView
  • Since onCreateOptionsMenu() is invoked each time a Fragment is created, or subsequently comes into view (e.g. Swipe); the SearchView's OnQueryTextListener is updated to the corresponding Fragment
  • Lastly, there was a line in OP's main Fragment containing the ViewPager2, which was removed: viewPager2.setOffscreenPageLimit(5); that caused each Fragment provided by the FragmentStateAdapter to instantiate and mutate the SearchView's OnQueryTextListener each time a Fragment was created. Removing the line made sure that only the Fragment that was in view was bound to the Toolbar's SearchView.

If any more code is desired, i'd be happy to post what I have, and if I come up with a solution using viewPager2.setOffscreenPageLimit(5); i.e. caching, i'll post that as well

clcuenca
  • 86
  • 1
  • 2