SearchView with multiple fragments using viewpager in android
Asked Answered
H

5

15

I want to implement SearchView with multiple fragments present in a viewPager. All fragemnts contains lists and I want to filter those lists and create a new ListView which has categorization of results based upon which fragment it belongs to.

But my searchView is not working with one fragment.

Here is my main activity:

package com.codeon.directory;

import android.app.SearchManager;
import android.content.Context;
import android.os.Bundle;
import android.support.design.widget.TabLayout;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.SearchView;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.View;
import com.codeon.directory.fragments.FiveFragment;
import com.codeon.directory.fragments.FourFragment;
import com.codeon.directory.fragments.OneFragment;
import com.codeon.directory.fragments.SixFragment;
import com.codeon.directory.fragments.ThreeFragment;
import com.codeon.directory.fragments.TwoFragment;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by Nikhil Jain on 21-Sep-15.
 */
public class TabEffect extends AppCompatActivity {

    private TabLayout tabLayout;
    private ViewPager viewPager;
    public String pic[] = {"1","2","3","1","2","3","1","2","3","1","2","3","1","2","3"};
    public String state[] = {"A","B","C"};
    public String city[] = {"P","Q","R"};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.tablayout);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        getSupportActionBar().setDisplayShowHomeEnabled(true);
        getSupportActionBar().setHomeButtonEnabled(true);
        toolbar.setNavigationOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                onBackPressed();
            }
        });

        viewPager = (ViewPager) findViewById(R.id.viewpager);
        setupViewPager(viewPager);

        tabLayout = (TabLayout) findViewById(R.id.tabs);
        tabLayout.setupWithViewPager(viewPager);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.tab, menu);

        // Associate searchable configuration with the SearchView
        SearchManager searchManager =
                (SearchManager) getSystemService(Context.SEARCH_SERVICE);
        SearchView searchView =
                (SearchView) menu.findItem(R.id.action_search).getActionView();
        searchView.setSearchableInfo(
                searchManager.getSearchableInfo(getComponentName()));
        return true;
    }

    private void setupViewPager(ViewPager viewPager) {
        ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
        Bundle bundle = new Bundle();
        bundle.putStringArray("pic", pic);
        bundle.putStringArray("district", city);
        bundle.putStringArray("state", state);
        adapter.addFragment(new OneFragment(), "ONE FRAGMENT", bundle);
        adapter.addFragment(new TwoFragment(), "TWO FRAGMENT", bundle);
        adapter.addFragment(new ThreeFragment(), "THREE FRAGMENT", bundle);
        adapter.addFragment(new FourFragment(), "FOUR FRAGMENT", bundle);
        adapter.addFragment(new FiveFragment(), "FIVE FRAGMENT", bundle);
        adapter.addFragment(new SixFragment(), "SIX FRAGMENT", bundle);
        viewPager.setAdapter(adapter);
    }

    class ViewPagerAdapter extends FragmentPagerAdapter {
        private final List<Fragment> mFragmentList = new ArrayList<>();
        private final List<String> mFragmentTitleList = new ArrayList<>();

        public ViewPagerAdapter(FragmentManager manager) {
            super(manager);
        }

        @Override
        public Fragment getItem(int position) {
            return mFragmentList.get(position);
        }

        @Override
        public int getCount() {
            return mFragmentList.size();
        }

        public void addFragment(Fragment fragment, String title, Bundle args) {
            mFragmentList.add(fragment);
            mFragmentTitleList.add(title);
            fragment.setArguments(args);
        }

        @Override
        public CharSequence getPageTitle(int position) {
            return mFragmentTitleList.get(position);
        }
    }
}

This is my first fragment :

package com.codeon.directory.fragments;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListView;

import com.codeon.directory.R;
import com.codeon.directory.RecyclerAdapter;
import com.codeon.directory.customadapters.Listitems_new;

import java.util.ArrayList;

/**
 * Created by Nikhil Jain on 21-Sep-15.
 */
public class OneFragment extends Fragment {

    ListView list;
    private ArrayAdapter<String> listAdapter ;

    public OneFragment() {
        // Required empty public constructor
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        RecyclerView rootView = (RecyclerView) inflater.inflate(R.layout.fragment_one, container, false);
        // Inflate the layout for this fragment
        Bundle extras = getArguments();
        String pic[] = extras.getStringArray("pic");
        String state[] = extras.getStringArray("state");
        Log.e("VALUE",pic[0]+pic[1]+pic[2]);

        rootView.setLayoutManager(new LinearLayoutManager(rootView.getContext()));
        //listAdapter = new ArrayAdapter<>(getActivity(), android.R.layout.simple_list_item_1, android.R.id.text1, pic);
        rootView.setAdapter(new RecyclerAdapter(pic));
        return rootView;
    }
}

My SearchActivity:

package com.codeon.directory;

import android.app.Activity;
import android.app.SearchManager;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;

/**
  * Created by Nikhil Jain on 21-Sep-15.
*/
public class SearchActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.search);

    // Get the intent, verify the action and get the query
    Intent intent = getIntent();
    if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
        String query = intent.getStringExtra(SearchManager.QUERY);
        doMySearch(query);
        Log.e("QUERY", query);
    }
}

private void doMySearch(String query) {

}
}

This is my AndroidManifest.xml:

<activity
        android:name=".TabEffect"
        android:label="@string/tablayout"
        android:theme="@style/AppTheme" >
    </activity>
    <activity android:name=".SearchActivity" >
        <intent-filter>
            <action android:name="android.intent.action.SEARCH" />
        </intent-filter>
        <meta-data android:name="android.app.searchable"
            android:resource="@layout/searchable"/>
    </activity>

This is my Searchable layout:

<?xml version="1.0" encoding="utf-8"?>
<searchable
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:label="@string/app_name"
    android:hint="@string/search_hint"
    android:layout_height="wrap_content"
    android:layout_width="match_parent"/>

For simple, I want to implement searchView like in Whatsapp.

enter image description here

Hellenhellene answered 24/9, 2015 at 14:17 Comment(5)
Have you got the solution?Ultimate
Did you figure it out?Nonsmoker
found any solution?Slang
Good structuring with the question. Any solutions yet ?!Otis
have you found a solution?Tuff
M
3

@Chintan is right. We need to use ViewModel. Follow this.

  1. Create SearchViewModel:

'''

private MutableLiveData<String> query= new MutableLiveData<String>();

public void setQuery(String queryData)
{
    query.setValue(queryData);
}

public LiveData<String> getQuery() {
    return query;
}

'''

  1. SearchParentFragment

'''

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

    final MenuItem myMenuItem = menu.findItem(R.id.search_icon);

    searchViewModel = new ViewModelProvider(requireActivity()).get(SearchViewModel.class);

    searchView = (SearchView) myMenuItem.getActionView();
    searchView.setQueryHint("Search");
    searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
        @Override
        public boolean onQueryTextSubmit(String query) {
            return false;
        }

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

'''

  1. For each Child Fragment (tabs)

'''

public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    searchViewModel = new ViewModelProvider(requireActivity()).get(SearchViewModel.class);
    searchViewModel.getQuery().observe(getViewLifecycleOwner(), new Observer<String>() {
        @Override
        public void onChanged(String s) {
            if (s!=null)
            {adapter.getFilter().filter(s);
        }
    });
}

'''

A single query will work for all tabs.) I studied it for a long time, but this solution works for me.

Marozas answered 22/3, 2021 at 11:16 Comment(0)
J
2

I got my fragments have list with one Searchview working by using following code.. Place the code in each fragment where you want to

 @Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);

    if (isVisibleToUser)
    {
       search_bar.setOnQueryTextListener(this);
        if(listAdapter!=null)
            listAdapter.getFilter().filter(search_bar.getQuery());
    }
}

Screenshots: Chats tab is active Contacts tab is active

Julian answered 7/12, 2017 at 5:34 Comment(1)
need full code linkBambino
N
1

Below hint may help you

public class AnyActivity extends AppCompatActivity { private ListenFromActivity activityListener1; }

then define interface with separate file

public interface ListenFromActivity { void doSearchInFragment(String SearchKey); }

now in your fragment

    public class Connections extends Fragment implements ListenFromActivity 
    { 
       public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) 
    {
      ((AnyActivity)Objects.requireNonNull(getActivity())).setActivityTab1Listener(Connections.this);

    }
    @Override
    public void doSearchInFragment(String SearchKey) {
    //pass to any network or local call.
    }
}
Negrillo answered 22/5, 2020 at 17:54 Comment(0)
L
0

If You wanna search your query to all fragment must use Viewmodel with Livedata. Set Your Query in Livedata then Your Livedata Observe on all Your Fragment.

This Code in viewPager side

val searchLiveData = MutableLiveData<String>()
searchLiveData.postValue("query")

This code in all Fragments

mainViewModel.searchLiveData.observe(viewLifecycleOwner, Observer { query ->
     //Add your code
})

//1
val liveData: MutableLiveData<Any>()
//2
liveData.value = "Hello"
//3
liveData.observe(this, Observer { 
  // Update UI  
})
Lechery answered 8/1, 2021 at 4:42 Comment(0)
P
0

Good answer Любовь,realy help me.ViewModel fits well with fragments. So if you want to trigger search from MainActivity. You need to create: 1.ViewModel

public class SearchViewModel extends ViewModel {
public   MutableLiveData<String> query = new MutableLiveData<String>();
public void setQuery(String queryData) {

    query.setValue(queryData);
}
public LiveData<String> getQuery() {

    return query;
}

2.Create instance of it in activity where you want trigger and perform search.

searchViewModel = new ViewModelProvider(this).get(SearchViewModel.class);
SearchView searchView = (SearchView) bottomAppBar.getMenu().findItem(R.id.search).getActionView();
                    searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
                        @Override
                        public boolean onQueryTextSubmit(String query) {
                            Log.i("onQueryTextSubmit", query);
                            return false;
                        }

                        @Override
                        public boolean onQueryTextChange(String newText) {
                            searchViewModel.setQuery(newText);
                            Log.i("onQueryTextChange", newText);
                            return false;
                        }
                    });

3.Create instance of ViewModel in fragments to observe changes of it in mainActivity(in this way u pass data from activity to fragment)

searchViewModel = new ViewModelProvider(getActivity()).get(SearchViewModel.class);
    searchViewModel.getQuery().observe(getViewLifecycleOwner(), new Observer<String>() {
        @Override
        public void onChanged(String s) {
            if (s != null) {
                Log.i("onChanged",s);
                adapter.getFilter().filter(s);
                Log.i("filter",s);
            }
        }
    });

4.Override and implement custom getFilter in your adapter (only if u supply custom object to it) if its array of strings,getFilter now how to work with it.

 @Override
public Filter getFilter() {
    if (filter == null) {
        filter = new SearchFilter();
    }
    return filter;
}

private class SearchFilter extends Filter {

    @Override
    protected FilterResults performFiltering(CharSequence s) {

        FilterResults result = new FilterResults();
        if(s != null && s.toString().length() > 0)
        {
            s = s.toString().toLowerCase();
            ArrayList<Word> filteredItems = new ArrayList<Word>();

            for(int i = 0, l = searchList.size(); i < l; i++)
            {
                if(searchList.get(i).getmDefaultTranslation().toLowerCase().contains(s))
                {
                    Word x = new Word(searchList.get(i).getmDefaultTranslation(),searchList.get(i).getmMiwokTranslation(),
                            searchList.get(i).getmImageResourceId(),searchList.get(i).getmAudioResourceId());
                    filteredItems.add(x);
                   
                }
            }
            result.count = filteredItems.size();
            result.values = filteredItems;
        }else {
            result.count = searchList.size();
            result.values = searchList;
        }

        return result;
    }

    @SuppressWarnings("unchecked")
    @Override
    protected void publishResults(CharSequence s,
                                  FilterResults results) {

        numbersWords = (ArrayList<Word>)results.values;
        Log.i("new search", String.valueOf(results));
        notifyDataSetChanged();
    }

Sorry for my technical language!!! And here is the link for my repo where u can check full implementation of search with multiple fragments(using ViewModel) https://github.com/artnkfv/Multiscreen_App/tree/main_v1.1

Paine answered 3/4, 2021 at 21:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.