I have many fragments they're shown in 2 tab layouts using FragmentStatePagerAdapter in each fragment there is a Recycler view and I want to use a search bar in the app bar to filter results.
First I did this using the onQueryTextChange listener in the onCreateOptionsMenu and it worked fine with a couple fragments but when I added the implementation to the other fragments (just ctrl+c and ctrl+v) it stopped working, no results even on fragments that used to work i then read here that it was better to stick the onQueryTextChange listener in onPrepareOptionsMenu in an attempt to avoid an issue with invalidateOptionsMenu but i decided to give that a try which also worked and then when i added the methods to all my other fragments yet again it fails but it does work on a handful of fragments, oddly these happen to be all attached to the same parent fragment but the code for the 4 parent fragments, and for calling them is identical.
A different way around this I've read is creating an interface and using that from my main activity by getting a reference to the current fragment but then id have to get the currently showing fragment from my viewpager which i dont know is possible can anyone weigh in on this for me,
Many thanks
And thanks for the great edit lol
EDIT
Tried the interface approach to no avail although I'm still a beginner i do need to find the attached fragment and with a fragmentstateviewpager its just not possible without using hacks there must be some reason why it works in some and not in others and sometimes not at all
Edit 2
So im still fiddling with this and ive had almost no replies so lets flesh this out a little so i was adding the menu layout in the main activity like this
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.dashboard, menu);
SearchView searchView =
(SearchView)menu.findItem(R.id.action_search).getActionView();
SearchManager searchManager = (SearchManager)
getSystemService(SEARCH_SERVICE);
searchView.setSearchableInfo(searchManager
.getSearchableInfo(getComponentName()));
return true;
}
and then adding a listener on to it from the fragment in onPrepareOptionsMenu like this
#Override
public void onPrepareOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
//in this instance we wont as it will create a duplicate
SearchView searchView = (SearchView)
menu.findItem(R.id.action_search).getActionView();
searchView.setOnQueryTextListener(null);
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener(){
#Override
public boolean onQueryTextSubmit(String query) {
return false;
}
#Override
public boolean onQueryTextChange(String newText) {
showResults(newText);
return false;
}
});
super.onPrepareOptionsMenu(menu);
}
and i have called setHasOptionsMenu(true) in onCreateView of the fragment, this works perfectly but i have about 20 fragments to cycle through and when I add this to the other fragments it fails it either does nothing or makes the view blank or in rare occasions works, but that for me says my code is okay and maybe its a lifecycle thing, ive tried calling it from the onCreateOptionsMenu of the fragments and achieved the same results, and ive tried not calling anything from the MainActivity in onCreateOptions except inflating the menu and allow the fragments to call the search activity using
SearchView searchView = (SearchView)menu.findItem
(R.id.action_search).getActionView();
SearchManager searchManager = (SearchManager)
getActivity().getSystemService(getActivity().SEARCH_SERVICE);
searchView.setSearchableInfo(searchManager.getSearchableInfo
(getActivity().getComponentName()));
which again works up to around 8 fragments but my 20 or so just causes it to fall on its sword, is there something im not doing that could help
Edit 3
Okay so by adding some, checking it, adding some more, checking it, it seems to be a problem with my parent fragments so I have main activity 4 fragments that each hold a fragment state pager that each holds 7 or so fragments if I add the methods for the query listener to the first 7 or so fragments in the first parent fragment they all work beautifully, if I then add the methods to the next set of 7 or so fragments in the second parent only the second parents child fragments work, if I then quit my app and open it again only the first parents fragments work, will continue investigating any help appreciated I'll post the code for my parent fragments here soon.
EDIT 4
Just going to add the code i use for the parent fragments and the fragmentstatepager from my main activity
so from my Main activity i set the fragmentstatepager like this
private void setupViewPager(ViewPager viewPager) {
ViewPagerAdapter adapter = new
ViewPagerAdapter(getSupportFragmentManager());
adapter.addFrag(new sentenceMakers(), "QUICKS");
adapter.addFrag(new tabFragOne(), "NOUNS");
adapter.addFrag(new tabFragTwo(), "VERBS");
adapter.addFrag(new tabFragThree(), "OBJECTS");
viewPager.setAdapter(adapter);
}
class ViewPagerAdapter extends FragmentStatePagerAdapter {
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 void restoreState(Parcelable arg0, ClassLoader arg1) {
//do nothing here! no call to super.restoreState(arg0, arg1);
}
#Override
public int getCount() {
return mFragmentList.size();
}
public void addFrag(Fragment fragment, String title) {
mFragmentList.add(fragment);
mFragmentTitleList.add(title);
}
#Override
public CharSequence getPageTitle(int position) {
return mFragmentTitleList.get(position);
}
}
and my parent fragments look like this
public class sentenceMakers extends Fragment{
public ImageView imageView;
private ViewPager viewPager;
public static TabLayout tabLayout;
public sentenceMakers() {
// Required empty public constructor
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState){
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate
(R.layout.tab_frag_one, container, false);
// Inflate the layout for this fragment
//setRetainInstance(true);
viewPager = (ViewPager) rootView.findViewById(R.id.viewpager);
setupViewPager(viewPager);
tabLayout = (TabLayout) rootView.findViewById(R.id.tabs);
tabLayout.setupWithViewPager(viewPager);
setupTabIcons();
return rootView;
}
#Override
public void onActivityCreated(Bundle savedInstanceState){
super.onActivityCreated(savedInstanceState);
}
private void setupTabIcons() {
TextView tabZero2 = (TextView)
LayoutInflater.from(getActivity()).inflate(R.layout.custom_tab, null);
tabZero2.setText("FAVOURITES");
//tabOne.setGravity(View.TEXT_ALIGNMENT_CENTER);
tabZero2.setCompoundDrawablesWithIntrinsicBounds(0,
R.drawable.ic_star_white_24dp, 0, 0);
tabLayout.getTabAt(0).setCustomView(tabZero2);
TextView tabZero = (TextView)
LayoutInflater.from(getActivity()).inflate(R.layout.custom_tab, null);
tabZero.setText("FREQUENTS");
//tabOne.setGravity(View.TEXT_ALIGNMENT_CENTER);
tabZero.setCompoundDrawablesWithIntrinsicBounds(0,
R.drawable.ic_people_outline_white_24dp, 0, 0);
tabLayout.getTabAt(1).setCustomView(tabZero);
TextView tabOne = (TextView)
LayoutInflater.from(getActivity()).inflate(R.layout.custom_tab, null);
tabOne.setText("PRONOUNS");
//tabOne.setGravity(View.TEXT_ALIGNMENT_CENTER);
tabOne.setCompoundDrawablesWithIntrinsicBounds(0,
R.drawable.ic_accessibility_white_24dp, 0, 0);
tabLayout.getTabAt(2).setCustomView(tabOne);
TextView tabTwo = (TextView)
LayoutInflater.from(getActivity()).inflate(R.layout.custom_tab, null);
tabTwo.setText("CONJUCTIONS");
tabTwo.setCompoundDrawablesWithIntrinsicBounds(0,
R.drawable.ic_add_white_24dp, 0, 0);
tabLayout.getTabAt(3).setCustomView(tabTwo);
TextView tabThree = (TextView)
LayoutInflater.from(getActivity()).inflate(R.layout.custom_tab, null);
tabThree.setText("ADJECTIVES");
tabThree.setCompoundDrawablesWithIntrinsicBounds(0,
R.drawable.ic_favorite_border_white_24dp, 0, 0);
tabLayout.getTabAt(4).setCustomView(tabThree);
tabLayout.getTabAt(0).getCustomView().setSelected(true);
}
private void setupViewPager(ViewPager viewPager) {
ViewPagerAdapter adapter = new
ViewPagerAdapter(getChildFragmentManager());
adapter.addFrag(new favouriteCards(), "FAVOURITES");
adapter.addFrag(new predictedCards(), "FREQUENTS");
adapter.addFrag(new pronouns(), "PRONOUNS");
adapter.addFrag(new conjuctions(), "CONJUNCTIONS");
adapter.addFrag(new Others(), "ADJECTIVES");
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 addFrag(Fragment fragment, String title) {
mFragmentList.add(fragment);
mFragmentTitleList.add(title);
}
}
}
still struggling with this and i cannot for the life of me work out why it would work in one lot of fragments untill i add it to the next set, its the same thing with the same code it must just be initializing the last fragments that are asking for it can anyone help me here?
Thanks for any help
Basically, there is a thing that you have to keep in mind when you use fragments: do not keep references to your fragments: just create them and add to your layout, or provide to your ViewPager but then use other methods to retrieve them, like FragmentManager.findFragmentBy...
That said, your code shoud be (let me simplify with just two fragments):
Main activity
private void setupViewPager(ViewPager viewPager) {
ViewPagerAdapter adapter = new MyViewPagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(adapter);
}
class MyViewPagerAdapter extends FragmentStatePagerAdapter {
public ViewPagerAdapter(FragmentManager manager) {
super(manager);
}
#Override
public Fragment getItem(int position) {
switch(position) {
case 0:
return new sentenceMakers();
case 1:
return new tabFragOne();
// add here fragments for any other position
}
}
#Override
public int getCount() {
return 2;
}
#Override
public CharSequence getPageTitle(int position) {
switch(position) {
case 0:
return "QUICKS";
case 1:
return "NOUNS";
// add here titles for any other position
}
}
}
sentenceMakers
The code you will have to use in your sentenceMakers Fragment is very similar to the previous one, but you will have to use the child fragmentManager (as you did in your code) and again, do not keep your fragments in a List, let the system create them when needed.
ok i fixed it so the problem is that the parent fragmentstatepager loads fragmentA + fragmentB into memory, then the child fragmentstatepagers load there own childfragmentA + childfragmentB so we now have 2 parents and 4 children, onPrepareOptionsMenu is called from the child fragments so the the first is loaded childfragmentA(child of fragmentA) and then childFragmentA(child of fragmentB) is loaded and steals the search view, my 'fix' for this is probably a little crude i'm self taught and i'm not very aware of how to manage memory or if its bad to keep hold of references etc, i digress, in the parent fragment i check which fragment is visible using
setMenuVisibility(final boolean visible)
and in there i set a public static boolean and check for it in my childfragments and it works flawlessly for me as mentioned this is probably a terrible thing to do hopefully someone here can give a better solution
check which parent is visible
public static boolean tabFragOneVisible;
#Override
public void setUserVisibleHint(boolean isVisible){
super.setUserVisibleHint(isVisible);
if(!isVisible){
tabFragOneVisible = false;
}else{
tabFragOneVisible = true;
}
}
check if parent is visible hook up search view
#Override
public void onPrepareOptionsMenu(Menu menu) {
// need to check if fragment is visible
if (tabFragOne.tabFragOneVisible) {
SearchView searchView = (SearchView)
menu.findItem(R.id.action_search).getActionView();
SearchManager searchManager = (SearchManager) getActivity()
.getSystemService(getActivity().SEARCH_SERVICE);
searchView.setSearchableInfo(searchManager
.getSearchableInfo(getActivity().getComponentName()));
// searchView.setOnQueryTextListener(null);
searchView.setOnQueryTextListener(new
SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String query) {
return false;
}
#Override
public boolean onQueryTextChange(String newText) {
showResults(newText);
return false;
}
});
}
else{
}
super.onPrepareOptionsMenu(menu);
}
Maybe, it'll still help someone struggling to make one SearchView work for multiple Fragments. I found that onQueryTextListener would work on Fragment 1 (where the SearchView is initially created) but would not fire on Fragment 2,3, etc.
Fragments 2 worked when onPrepareOptionsMenu is overridden and onViewCreated includes a setHasOptionsMenu(true). For example:
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
setHasOptionsMenu(true);
...the rest of your code goes here...
}
#Override
public void onPrepareOptionsMenu(Menu menu) {
MenuItem item = menu.findItem(R.id.action_search);
SearchView searchView = (SearchView) item.getActionView();
searchView.setOnQueryTextListener(this);
super.onPrepareOptionsMenu(menu);
}
#Override
public boolean onQueryTextSubmit(String query) {
return false;
}
#Override
public boolean onQueryTextChange(String newText) {
Toast.makeText(getActivity(),"It Worked!!",Toast.LENGTH_SHORT).show();
return true;
}
Related
I have a tab layout with 2 fragment and I have a toolbar with different options that belong to the activity which hosts the view pager.
When I click on a toolbar option, it clean the data from DB that are used in the fragment and then it should refresh it to apply changes at screen.
But I can't find a way to refresh the fragment from the activity.
Here is the fragment adapter :
public class FragmentAdapter extends FragmentPagerAdapter
{
private final List<Fragment> lstFragment = new ArrayList<>();
private final List<String> lstTitles = new ArrayList<>();
public FragmentAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int i) {
return lstFragment.get(i);
}
#Nullable
#Override
public CharSequence getPageTitle(int position) {
return lstTitles.get(position);
}
#Override
public int getCount() {
return lstTitles.size();
}
public void AddFragment (Fragment fragment , String title)
{
lstFragment.add(fragment);
lstTitles.add(title);
}
}
Here is the way I call it in the fragments in main :
FragAdapter = new FragmentAdapter(getSupportFragmentManager());
((FragmentAdapter) FragAdapter).AddFragment(new FragmentProgramme(),"Programmes");
((FragmentAdapter) FragAdapter).AddFragment(new FragmentPlanning(),"Agenda"); //FRAGMENT I WANT TO REFRESH
mviewpager.setAdapter(FragAdapter);
mtablayout = (TabLayout) findViewById(R.id.main_tabs);
mtablayout.setupWithViewPager(mviewpager);
In the main, I have the option on the toolbar and I would like to do something like this :
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int pos = item.getItemId();
switch (pos)
{
DatabaseAgenda.getInstance(this).dropDB(); //CLEAN DB
// I would like to find a function like this : ((FragmentAdapter) FragAdapter).refresh(FragmentPlanning, "Agenda");
break;
}
return super.onOptionsItemSelected(item);
}
The point is to simply destroy the fragment because all the data must be cleaned from screen and then recreate it so the users can add new data to it
I hope this is clear, thank you for your hlelp
I have found a lot answers but never what I was really looking for
You can override the method setUserVisibleHint inside fragments to detect when it is visible. Data can be refreshed inside this method. Selecting the items of pageradapter programatically triggers setUserVisibleHint of present fragment. You would not need destroying fragments each time.
I have 3 fragments in a TabLayout as seen here http://imgur.com/a/Z9dTQ
Whenever I start the application, it opens the explorer tab, and I can switch to the search tab and the searchview works perfectly. If I switch to explorer and back to search, it still works.
My SearchView does not use a searchable activity, but instead searches with an onQueryTextChange listener. Below the SearchView is a LinearLayout with 30 TextViews whose text are changed by searching.
However, if I switch to the quiz tab and back to search, the SearchView text remains, but the TextViews are reset to their default values of "gone", like so: http://imgur.com/a/L4RvE. Trying to search now using the SearchView does not work.
It seems that switching to the quiz tab deflates my search layout, and when I switch back, it inflates the search layout but does not instantiate the SearchView properly. When I try to search again, OnQueryTextChange is not called. I cannot figure out why it does this.
The problem started when I added a SearchView to QuizLayout.xml, and added code for a second SearchView to the onCreateOptionsMenu in MainActivity for the quiz tab. However even after commenting it out and making sure all IDs were correct, the problem still happens.
Below is my code, with some (hopefully) irrelevant code omitted.
My SearchFragment:
package com.example.ryans45attcdie.chess;
public class SearchFragment extends Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.search_fragment, container, false);
return v;
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
searchLayout =
(LinearLayout)getView().findViewById(R.id.searchLayoutS);
}
}
My QuizFragment: (empty for debugging)
public class QuizFragment extends Fragment {}
My MainActivity:
public class MainActivity extends AppCompatActivity {
TextView sname1;//(etc.)
ArrayList<TextView> masterNameListS;
List<Fragment> fragments = new Vector<>();
ArrayList<String> listItems = new ArrayList<String>();
ArrayAdapter<String> adapter;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//set up fragments in tabs
fragments.add(Fragment.instantiate(this, QuizFragment.class.getName()));
fragments.add(Fragment.instantiate(this,
ExplorerFragment.class.getName()));
fragments.add(Fragment.instantiate(this,
SearchFragment.class.getName()));
PagerAdaptor adaptor = new PagerAdaptor(getSupportFragmentManager(),
fragments);
ViewPager pager = (ViewPager) findViewById(R.id.viewPager);
pager.setAdapter(adaptor);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
tabLayout.setupWithViewPager(pager);
tabLayout.getTabAt(0).setText("QUIZ");
tabLayout.getTabAt(1).setText("EXPLORE");
tabLayout.getTabAt(2).setText("SEARCH");
adapter = new ArrayAdapter<String>(getApplicationContext(),
android.R.layout.list_content, listItems);
pager.setCurrentItem(1);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
sname1 = (TextView) findViewById(R.id.sname1); //(etc.)
final ArrayList<TextView> masterNameListS = new ArrayList<>();
masterNameListS.add(sname1); //(etc.)
// Get the SearchView and set the searchable configuration
SearchManager searchManagerS = (SearchManager)
getSystemService(Context.SEARCH_SERVICE);
SearchView searchViewS = (SearchView) findViewById(R.id.searchViewS);
// Assumes current activity is the searchable activity
ComponentName cnS = new ComponentName(this, SearchableActivity.class);
searchViewS.setSearchableInfo(searchManagerS.getSearchableInfo(cnS));
searchViewS.setIconifiedByDefault(false); // Do not iconify the widget;
expand it by default
searchViewS.setOnQueryTextListener(new SearchView.OnQueryTextListener()
{
#Override
public boolean onQueryTextSubmit(String s) {
return true;
}
#Override
public boolean onQueryTextChange(String s) {
//parse search string and set TextView texts here
return true;
}
});
return true;
}
#Override
public booleafn onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
And PagerAdapter:
package com.example.ryans45attcdie.chess;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.view.WindowManager;
import java.util.List;
public class PagerAdaptor extends FragmentPagerAdapter {
private List<Fragment> fragments;
public PagerAdaptor(FragmentManager fm, List<Fragment> fragments) {
super(fm);
this.fragments = fragments;
}
#Override
public Fragment getItem(int i) {
return fragments.get(i);
}
#Override
public int getCount() {
return fragments.size();
}
}
My QuizLayout.xml is empty.
My SearchLayout.xml creates all the TextViews with no text and Visibility.GONE.
Thanks very much for the help guys,
Stephen
Solved it :)
The issue was that ViewPager keeps, by default, only one off-screen tab in memory. Because my explorer tab was opened first, this was stored in memory. When I switched from search to quiz, my ViewPager decided to delete the search tab, and keep the explorer tab.
To fix this, put your_View_Pager_here.setOffscreenPageLimit(number_to_store); in your MainActivity onCreate method.
So.. I have a Fragment containing ViewPager with two more Fragments in it which serves as search tabs. That means 3 different Java classes, 1 for container, the 2 are for the contents.
The behavior I wanted was : When user presses the search button, types something, and submit the search in the base Activity, the app overrides onQueryTextSubmit to start the pager Fragment and getting the query there to directly search in the first Fragment in the pager. When user swipe to the next Fragment, the SearchView persists, along with its query and also perform search on the second Fragment using said query.
The behavior I am getting is.. When user swipes to the next Fragment, the searchmenu collapses and the keyword is gone..
This is how I code the SearchVenu in the Activity
#Override
public boolean onQueryTextSubmit(String query) {
searchFragment = new SearchFragment();
Bundle searchBundle = new Bundle();
keyword = searchView.getQuery().toString();
searchBundle.putString("searchQuery", keyword);
searchFragment.setArguments(searchBundle);
backstackCount = manager.getBackStackEntryCount();
if (backstackCount >= 2) {
manager.executePendingTransactions();
if (manager.getBackStackEntryAt(backstackCount - 1).getName().equals("searchTag")) {
} else {
replaceFragment(searchFragment, searchTag);
}
} else {
replaceFragment(searchFragment, searchTag);
}
return false;
The adapter :
mAdapter = new MyPagerAdapter(getChildFragmentManager(), bundle);
...
private class MyPagerAdapter extends FragmentStatePagerAdapter {
private Bundle fragmentBundle;
public MyPagerAdapter(FragmentManager fm, Bundle data) {
super(fm);
fragmentBundle = data;
}
#Override
public Fragment getItem(int pos) {
/*Fragment f = new Fragment();
f.setArguments(this.fragmentBundle);
return f;*/
switch(pos) {
case 0: return SearchFriendFragment.newInstance(fragmentBundle);
case 1: return SearchShopFragment.newInstance(fragmentBundle);
default: return SearchFriendFragment.newInstance(fragmentBundle);
}
}
#Override
public CharSequence getPageTitle(int position) {
return CONTENT[position % CONTENT.length];
}
#Override
public int getCount() {
//return 3;
return CONTENT.length;
}
}
This is how I initialize the search in one of the Fragments
#Override
public void onPrepareOptionsMenu(Menu menu) {
menu.clear();
super.onPrepareOptionsMenu(menu);
getActivity().getMenuInflater().inflate(R.menu.menu_search, menu);
searchViewBtn = menu.findItem(R.id.menu_search);
searchView = (SearchView) MenuItemCompat.getActionView(searchViewBtn);
I am well aware by doing menu.clear() will keep refreshing the menu on switching Fragment.. But I don't know what to do to get the correct behavior..
Update menu_search.xml
<item
android:id="#+id/menu_search"
android:orderInCategory="200"
android:title="Search"
android:icon="#drawable/iconcariheader"
app:showAsAction="ifRoom"
app:actionViewClass="android.support.v7.widget.SearchView"></item>
use my suggestion like this
public boolean onOptionsItemSelected(MenuItem item)
{
switch(item.getItemId())
{
case R.id.menu_search:
searchView = (SearchView) item.getActionView();
searchView.setOnQueryTextListener
(new SearchView.OnQueryTextListener()
{
#Override
public boolean onQueryTextSubmit(String query) {
// call your search function
return true;
}
#Override
public boolean onQueryTextChange(String newText) {
// call your search function
return true;
}
});
break;
}
return super.onOptionsItemSelected(item);
}
Hope this will help and let me know for further.
On my screen I have 2 containers - left for 3 fragments in view pager, right for single fragment. From this on the right I increment some temp variable and through inteface I pass this variable to fragments. I switch fragments in view pager and everything seems to act all right. But, there are two problems.
First is that when I start my app and try to actualize temp variable in third fragment in view pager there is NPE. And of course it should be, because at this point third fragment is not initialized (view pager only initialize actual fragment and the ones on his sides, to be able to slide between fragments). How can I initialize third fragment at the begining? I thought I can store data temporarily in second fragment and when second is initialized I can pass the data to third, but it seems not good solution.
Second question is when I initialize all fragments by sliding on it and I come back to first fragment view of third is gone (but it's initialized). When I actualize temp variable and slide to third fragment I can see this variable but after +- one second. Can someone explain me why? Without this knowledge I can't solve this problem :/
Here you have some code of mine:
public class ThirdFragment extends Fragment {
View thisView;
TextView tempTextView;
String iterator;
public AchievFragment() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
iterator = "Start";
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
thisView = inflater.inflate(R.layout.fragment_third, container, false);
tempTextView= (TextView) thisView.findViewById(R.id.tempTextView);
tempTextView.setText(iterator);
return thisView;
}
public void getVariable(String text) {
iterator = text;
tempTextView.setText(iterator);
}
So it's third fragment class. At the beginning I initialize iterator (it's this temp variable) as a global variable to avoid npe after initializing fragments. And in onCreateView i set the view of TextView to value of this variable. Should work fine, but this +-1 sec offset makes me sad.
I think this sample of code should be enough, the rest is standard I suppose, but if anyone will be really interested I'll past the rest.
I really hope you will understand what I just wrote.
Here is the main (hosting) activity code:
public class MainActivity extends AppCompatActivity implements OnFragmentInteractionListener {
ViewPager mViewPager;
FragmentPageAdapter ft;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mViewPager = (ViewPager) findViewById(R.id.pager_container);
ft = new FragmentPageAdapter(getSupportFragmentManager());
mViewPager.setAdapter(ft);
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
RightFragment gameFragment = new RightFragment();
ft.replace(R.id.rightFragment_container, rightFragment,"RightFragment");
ft.commit();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
return super.onOptionsItemSelected(item);
}
#Override
public void OnUpdateFirst(String text) {
FirstFragment firstFragment = (FirstFragment) ft.instantiateItem(mViewPager,0);
firstFragment.getVariable(text);
}
#Override
public void OnUpdateSecond(String text) {
SecondFragment secondFragment = (SecondFragment) ft.instantiateItem(mViewPager,1);
secondFragment.getVariable(text);
}
#Override
public void OnUpdateThird(String text) {
ThirdFragment thirdFragment = (ThirdFragment) ft.instantiateItem(mViewPager,2);
thirdFragment.getVariable(text);
}
}
Fragment Page Adapter code:
public class FragmentPageAdapter extends FragmentPagerAdapter {
public FragmentPageAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int arg0) {
switch (arg0)
{
case 0:
return new FirstFragment();
case 1:
return new SecondFragment();
case 2:
return new ThirdFragment();
default:
break;
}
return null;
}
#Override
public int getCount() {
return 3;
}
Expection when I try to actualize variable on third fragment before I initialize it (in example right after I start app)
06-14 16:47:25.621 27246-27246/com.package.app E/AndroidRuntime﹕ FATAL EXCEPTION: main
java.lang.NullPointerException
at com.package.app.ThirdFragment.getVariable(ThirdFragment.java:37)
at com.package.app.MainActivity.OnUpdateThird(MainActivity.java:59)
at com.package.app.RightFragment$3.onClick(RightFragment.java:57)
at android.view.View.performClick(View.java:4101)
at android.view.View$PerformClick.run(View.java:17082)
at android.os.Handler.handleCallback(Handler.java:615)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4940)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:798)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:565)
at dalvik.system.NativeStart.main(Native Method)
As to your first question you can call setOffscreenPageLimit(2) method on your ViewPager right after initializing it. By default it is set to 1 that means that adapter creates one page which is on the screen right now and one that is next.
Right now I have an activity using a viewpager to display a several fragments. each of those fragments has implemented a Context Action Bar in the fragment. I am trying to make it where if the user scrolls or tabs between the fragments, the ActionBar for the previously selected fragment is dismissed.
I think I need to make some sort of call to the CAB .finish()in the fragment from my OnPageChangeListener() however I am not entirely sure how or where to do that.
Create should a public function in each fragment which can be called to finish the ActionMode. Could look like this
public void finishActionMode(){
[YOUR_ACTIONMODE_VARIABLE].finish();
}
Then in the activity you keep your ViewPager you should somehow keep or get a reference to the fragment in the ViewPager which should close its ActionMode, and then in your onPageSelected you can call `[YOUR_FRAGMENT_REFERENCE].finishActionMode();
Like this:
mPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageSelected(int position) {
[YOUR_FRAGMENT_REFERENCE].finishActionMode();
}
...
});
For keeping a reference to a ViewPagers fragments look here: Retrieve a Fragment from a ViewPager
You don't have to create individual Contextual Action Bar(CAB) for every fragments. You can simply create a single STATIC CAB in the TabbedActivity(Activity with pager) and use them anytime when needed.
Here is my code snippet of TabbedActivity.java
public class TabbedActivity extends AppCompatActivity {
public static ActionMode uniActionMode=null;
private ViewPager mViewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int
positionOffsetPixels) {
if(uniActionMode!=null)
uniActionMode.finish();
}
#Override
public void onPageSelected(int position)
{
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
}
The mViewPager.addOnPageChangeListener is used to check if the user moves through the fragments. Now all you have to do is create an ActionMode from anywhere and then pass the value to the static uniActionMode variable.
mActionModeCallback = new ActionMode.Callback() {
#Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
// Inflate a menu resource providing context menu items
MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.menu_selection, menu);
return true;
}
#Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
#Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch (item.getItemId()) {
case R.id.action_delete:
mode.finish();
return true;
case R.id.action_mark_read:
mode.finish();
return true;
}
return false;
}
#Override
public void onDestroyActionMode(ActionMode mode) {
}
};
TabbedActivity.uniActionMode= v.startActionMode(mActionModeCallback);
Here the TabbedActivity.uniActionMode references the ActionMode Object of the Tabbed Activity. Thus the callbacks are passed to the TabbedActivity.uniActionMode.