I have a NavigationDrawer which I use to switch between Fragments. What i would like to do is have a button in one of my fragments which acts as a 'shortcut' to another Fragment in the NavigationDrawer.
In the NavigationDrawer I switch fragments like this:
private class DrawerItemClickListener implements
ListView.OnItemClickListener {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
selectItem(position);
}
}
public void selectItem(int position) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager
.beginTransaction();
String fragmentTag = String.valueOf(position);
FragmentBase fragment = (FragmentBase) fragmentManager
.findFragmentByTag(fragmentTag);
if (null == fragment) {
fragment = createFragmentByPosition(position);
}
if (null == fragment)
return;
if (fragment.isAdded()) {
fragmentTransaction.show(fragment);
} else {
fragmentTransaction.replace(R.id.content_frame, fragment, fragmentTag);
}
if (mCurrentFragment != null) {
fragmentTransaction.hide(mCurrentFragment);
}
mCurrentFragment = fragment;
fragmentTransaction.commitAllowingStateLoss();
mDrawerList.setItemChecked(position, true);
setTitle(mNoterActivities[position]);
mDrawerLayout.closeDrawer(mDrawerList);
}
private FragmentBase createFragmentByPosition(int position) { // FragmentBase just extends Fragment
FragmentBase fragment = null;
if (position == 0) {
fragment = new Fragment1();
Bundle args = new Bundle();
fragment.setArguments(args);
} else if (position == 1) { // Reminder
fragment = new Fragment2();
Bundle args = new Bundle();
fragment.setArguments(args);
}
return fragment;
}
I'm not sure how I would go about doing this. I tried getting an instance of the NavigationDrawer class and then calling selectItem with the desired position, but this doesn't work as it gives an error "no view found".
In the NavigationDrawer class:
public Navigation_Drawer getInstance() {
if (null == instance) {
instance = new Navigation_Drawer();
}
return instance;
}
In FragmentB (position 1):
//onClick
Navigation_Drawer nd = new Navigation_Drawer().getInstance();
nd.selectItem(0); // Try to go to FragmentA
This seems far too simple so no wonder it doesn't work!
First, on selectItem method, using add method instead of replace method:
public void selectItem(int position) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
String fragmentTag = String.valueOf(position);
FragmentBase fragment = (FragmentBase) fragmentManager.findFragmentByTag(fragmentTag);
if (null == fragment) {
fragment = createFragmentByPosition(position);
}
if (null == fragment)
return;
if (fragment.isAdded()) {
fragmentTransaction.show(fragment);
} else {
// fragmentTransaction.replace(R.id.content_frame, fragment, fragmentTag);
fragmentTransaction.add(R.id.content_frame, fragment, fragmentTag);
}
if (mCurrentFragment != null) {
fragmentTransaction.hide(mCurrentFragment);
}
mCurrentFragment = fragment;
fragmentTransaction.commitAllowingStateLoss();
mDrawerList.setItemChecked(position, true);
setTitle(mNoterActivities[position]);
mDrawerLayout.closeDrawer(mDrawerList);
}
Second, getInstance method in Navigation_Drawer should not create a new Navigation_Drawer when instance is null, set instance to this in onCreate in Navigation_Drawer, then return instance when call getInstance:
private static Navigation_Drawer mInstance;
public static Navigation_Drawer getInstance() {
return mInstance;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
mInstance = this;
// other codes here:
}
The id to the QuickNoteFragment is 0, and to PendViewPager is 1. You can turn to PendViewPager in QuickNoteFragment:
Navigation_Drawer.getInstance().selectItem(1);
-
update1: how to pass data to fragment:
QuickNoteFragment and HistoryFragement have the same parent Class: FragmentBase, we add a method named onDataIn to receive data:
public class FragmentBase extends Fragment {
public void function onDataIn(Object data) {
}
}
We should change selectItem, add a paraments to receive data:
public void selectItem(int position, Object data) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
String fragmentTag = String.valueOf(position);
FragmentBase fragment = (FragmentBase) fragmentManager.findFragmentByTag(fragmentTag);
if (null == fragment) {
fragment = createFragmentByPosition(position);
}
if (null == fragment)
return;
// call onDataIn() method.
fragment.onDataIn(data);
if (fragment.isAdded()) {
fragmentTransaction.show(fragment);
} else {
// fragmentTransaction.replace(R.id.content_frame, fragment, fragmentTag);
fragmentTransaction.add(R.id.content_frame, fragment, fragmentTag);
}
if (mCurrentFragment != null) {
fragmentTransaction.hide(mCurrentFragment);
}
mCurrentFragment = fragment;
fragmentTransaction.commitAllowingStateLoss();
mDrawerList.setItemChecked(position, true);
setTitle(mNoterActivities[position]);
mDrawerLayout.closeDrawer(mDrawerList);
}
In order to make selectItem compatible, we should add a overloaded selectItem method.
public void selectItem(int postion) {
selectItem(position, null);
}
In this way, we do not need to change the old code where called selectItem and did not need pass a data to fragement.
Related
I've recently switched my ViewPager's adapter from FragmentPagerAdapter to FragmentStatePagerAdapter. However, whenever I return to my ViewPager the app crashes. This was not happening with FragmentPagerAdapter. The Logcat shows:
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object android.util.SparseArray.get(int)' on a null object reference
I'm in that awkward position where I don't know enough to understand what questions I should be asking. All of my searches have turned up nothing useful.
Logcat
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object android.util.SparseArray.get(int)' on a null object reference
at android.support.v4.app.FragmentManagerImpl.getFragment(FragmentManager.java:905)
at android.support.v4.app.FragmentStatePagerAdapter.restoreState(FragmentStatePagerAdapter.java:216)
at android.support.v4.view.ViewPager.onRestoreInstanceState(ViewPager.java:1455)
at android.view.View.dispatchRestoreInstanceState(View.java:17706)
at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:3745)
at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:3751)
at android.view.View.restoreHierarchyState(View.java:17684)
at android.support.v4.app.Fragment.restoreViewState(Fragment.java:415)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1454)
at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1759)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1827)
at android.support.v4.app.BackStackRecord.executeOps(BackStackRecord.java:797)
at android.support.v4.app.FragmentManagerImpl.executeOps(FragmentManager.java:2596)
at android.support.v4.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2383)
at android.support.v4.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManager.java:2338)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:2245)
at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:703)
at android.os.Handler.handleCallback(Handler.java:790)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6494)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
MainActivity.java
public class MainActivity extends AppCompatActivity
implements FragmentQuiz_Selection_Instruments.QuizSelectionInterface,
FragmentQuiz_Started.OnQuizExit,
FragmentQuiz_Selection_Topics.StartQuizInterface {
private DrawerLayout mDrawerLayout;
private Fragment mQuizFragment;
private Fragment mInstrumentsFragment;
private Fragment mReferenceFragment;
private ArrayList<String> mQuizSelection;
private ViewModel_ForegroundView viewModel;
private BottomNavigationView bottomNavigationView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Initialise mQuizSelection
mQuizSelection = new ArrayList<String>();
mQuizSelection.clear();
//Initialise bottomNavigationView
bottomNavigationView = findViewById(R.id.navigation_bottom);
//Set Bottom-Navigation icon
bottomNavigationView.getMenu().getItem(1).setChecked(true);
//Initialise ViewModel_ForegroundView
viewModel = ViewModelProviders.of(this).get(ViewModel_ForegroundView.class);
//Initialise ActionBar
final Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setHomeAsUpIndicator(R.drawable.ic_menu);
//Initialise Top-Navigation Drawer
mDrawerLayout = findViewById(R.id.drawer_layout);
NavigationView navigationView = findViewById(R.id.navigation_top);
// Set the onClickListener for the NavigationDrawer
navigationView.setNavigationItemSelectedListener(
new NavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
// set item as selected to persist highlight
item.setChecked(true);
// close drawer when item is tapped
mDrawerLayout.closeDrawers();
// Handle item clicks
int itemId = item.getItemId();
if (itemId == R.id.nav_top_ww) {
Fragment fragment = getSupportFragmentManager().findFragmentByTag("FragmentInstruments_WWind");
if (fragment == null) {
mInstrumentsFragment = FragmentInstruments_WWind.newInstance();
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.add(mInstrumentsFragment, "FragmentInstruments_WWind");
fragmentTransaction.commit();
} else {
mInstrumentsFragment = fragment;
}
} else if (itemId == R.id.nav_top_br) {
Fragment fragment = getSupportFragmentManager().findFragmentByTag("FragmentInstruments_Brass");
if (fragment == null) {
mInstrumentsFragment = FragmentInstruments_Brass.newInstance();
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.add(mInstrumentsFragment, "FragmentInstruments_Brass");
fragmentTransaction.commit();
} else {
mInstrumentsFragment = fragment;
}
} else if (itemId == R.id.nav_top_pp) {
Fragment fragment = getSupportFragmentManager().findFragmentByTag("FragmentInstruments_PercPit");
if (fragment == null) {
mInstrumentsFragment = FragmentInstruments_PercPit.newInstance();
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.add(mInstrumentsFragment, "FragmentInstruments_PercPit");
fragmentTransaction.commit();
} else {
mInstrumentsFragment = fragment;
}
} else if (itemId == R.id.nav_top_pu) {
Fragment fragment = getSupportFragmentManager().findFragmentByTag("FragmentInstruments_PercUnp");
if (fragment == null) {
mInstrumentsFragment = FragmentInstruments_PercUnp.newInstance();
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.add(mInstrumentsFragment, "FragmentInstruments_PercUnp");
fragmentTransaction.commit();
} else {
mInstrumentsFragment = fragment;
}
} else if (itemId == R.id.nav_top_sp) {
Fragment fragment = getSupportFragmentManager().findFragmentByTag("FragmentInstruments_StrPlu");
if (fragment == null) {
mInstrumentsFragment = FragmentInstruments_StrPlu.newInstance();
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.add(mInstrumentsFragment, "FragmentInstruments_StrPlu");
fragmentTransaction.commit();
} else {
mInstrumentsFragment = fragment;
}
} else if (itemId == R.id.nav_top_ky) {
Fragment fragment = getSupportFragmentManager().findFragmentByTag("FragmentInstruments_Keys");
if (fragment == null) {
mInstrumentsFragment = FragmentInstruments_Keys.newInstance();
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.add(mInstrumentsFragment, "FragmentInstruments_Keys");
fragmentTransaction.commit();
} else {
mInstrumentsFragment = fragment;
}
} else if (itemId == R.id.nav_top_sb) {
Fragment fragment = getSupportFragmentManager().findFragmentByTag("FragmentInstruments_StrBow");
if (fragment == null) {
mInstrumentsFragment = FragmentInstruments_StrBow.newInstance();
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.add(mInstrumentsFragment, "FragmentInstruments_StrBow");
fragmentTransaction.commit();
} else {
mInstrumentsFragment = fragment;
}
}
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.frame_layout, mInstrumentsFragment);
transaction.commit();
//Record foreground-fragment change
viewModel.recordForegroundFragment(mInstrumentsFragment);
//Set 'Quiz Exit' button's visibility to 'false,' set Quiz-Ext button.
viewModel.recordQuizBtnStatus(false);
setQuizExtBtn();
return true;
}
});
mDrawerLayout.addDrawerListener(
new DrawerLayout.DrawerListener() {
#Override
public void onDrawerSlide(View drawerView, float slideOffset) {
// Respond when the drawer's position changes
}
#Override
public void onDrawerOpened(View drawerView) {
// Respond when the drawer is opened
drawerView.bringToFront();
}
#Override
public void onDrawerClosed(View drawerView) {
// Respond when the drawer is closed
}
#Override
public void onDrawerStateChanged(int newState) {
// Respond when the drawer motion state changes
}});
// Bottom-Navigation Menu
bottomNavigationView.setOnNavigationItemSelectedListener(
new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
int itemId = item.getItemId();
if (itemId == R.id.nav_btm_quiz) {
if (mQuizFragment != null) {
String string = mQuizFragment.toString();
if (string.contains("Started") || string.contains("Topics")) {
viewModel.recordQuizBtnStatus(true);
}
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.frame_layout, mQuizFragment);
fragmentTransaction.commit();
//Record foreground-fragment change
viewModel.recordForegroundFragment(mQuizFragment);
} else {
Fragment fragment = getSupportFragmentManager().findFragmentByTag("FragmentQuiz_Selection_Instruments");
if (fragment == null) {
mQuizFragment = FragmentQuiz_Selection_Instruments.newInstance();
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.frame_layout, mQuizFragment, "FragmentQuiz_Selection_Instruments");
fragmentTransaction.commit();
viewModel.recordForegroundFragment(mQuizFragment);
} else {
mQuizFragment = fragment;
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.frame_layout, mQuizFragment);
fragmentTransaction.commit();
viewModel.recordForegroundFragment(mQuizFragment);
}
}
} else if (itemId == R.id.nav_btm_instruments) {
viewModel.recordQuizBtnStatus(false);
if (mInstrumentsFragment != null) {
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.frame_layout, mInstrumentsFragment);
fragmentTransaction.commit();
viewModel.recordForegroundFragment(mInstrumentsFragment);
} else {
Fragment fragment = getSupportFragmentManager().findFragmentByTag("FragmentInstruments_WWind");
if (fragment == null) {
mQuizFragment = FragmentInstruments_WWind.newInstance();
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.add(R.id.frame_layout, mQuizFragment, "FragmentInstruments_WWind");
fragmentTransaction.commit();
} else {
mQuizFragment = fragment;
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.frame_layout, fragment);
fragmentTransaction.commit();
}
}
} else if (itemId == R.id.nav_btm_reference) {
viewModel.recordQuizBtnStatus(false);
if (mReferenceFragment != null) {
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.frame_layout, mReferenceFragment);
fragmentTransaction.commit();
} else {
mReferenceFragment = FragmentReference.newInstance();
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.frame_layout, mReferenceFragment, "FragmentReference");
fragmentTransaction.commit();
}
}
//Set Quiz-Ext button's visibility.
setQuizExtBtn();
//Call 'invalidateOptionsMenu' to set the Quiz-Exit button's visibility.
invalidateOptionsMenu();
return true;
}
});
}
#Override
protected void onStart() {
super.onStart();
}
#Override
protected void onResume() {
super.onResume();
/**Display FragmentInstruments_WWind when opening the app for the first time.
* If the app is being resumed, use getForegroundFragment.
*/
if (viewModel.getForegroundFragment() == null) {
Fragment fragment = getSupportFragmentManager().findFragmentByTag("FragmentInstruments_WWind");
if (fragment == null) {
mInstrumentsFragment = FragmentInstruments_WWind.newInstance();
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.add(mInstrumentsFragment, "FragmentInstruments_WWind");
fragmentTransaction.commit();
} else {
mInstrumentsFragment = fragment;
}
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.frame_layout, mInstrumentsFragment);
transaction.commit();
//Record foreground-fragment change
viewModel.recordForegroundFragment(mInstrumentsFragment);
//Set Quiz-Exit Status
viewModel.recordQuizBtnStatus(false);
//Set 'Reference' icon as checked
bottomNavigationView.getMenu().getItem(1).setChecked(true);
} else if (viewModel.getForegroundFragment() != null) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
Fragment foregroundFragment = viewModel.getForegroundFragment();
transaction.replace(R.id.frame_layout, foregroundFragment);
transaction.commit();
//Record foreground-fragment change, set bottom-navigation icon
viewModel.recordForegroundFragment(foregroundFragment);
String fragment = foregroundFragment.toString();
if (fragment.contains("Quiz")) {
bottomNavigationView.getMenu().getItem(0).setChecked(true);
} else if (fragment.contains("Reference")) {
bottomNavigationView.getMenu().getItem(1).setChecked(true);
} else if (fragment.contains("Help")) {
bottomNavigationView.getMenu().getItem(2).setChecked(true);
}
}
}
#Override
protected void onPause(){
super.onPause();
//Actions onPause
viewModel.recordInstrumentsFragment(mInstrumentsFragment);
}
//Search function handled here
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the options menu from XML
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.action_bar, menu);
//Set 'Quiz Exit' button's visibility.
boolean status = viewModel.getQuizBtnStatus();
menu.findItem(R.id.ab_quiz_exit).setVisible(status);
return true;
}
//Handle action-bar button clicks
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
mDrawerLayout.openDrawer(GravityCompat.START);
return true;
case R.id.ab_quiz_exit:
onQuizExit();
}
return super.onOptionsItemSelected(item);
}
Parent Fragment
public class FragmentInstruments_Brass extends Fragment {
public static FragmentInstruments_Brass newInstance() {
FragmentInstruments_Brass fragment = new FragmentInstruments_Brass();
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Fragment screen orientation normal both portrait and landscape
getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_instruments, container, false);
//Setting ViewPager for each tab
ViewPager viewPager = view.findViewById(R.id.viewPager_instruments);
tabsToViewPager(viewPager);
//Set tabs inside toolbar
TabLayout tabLayout = view.findViewById(R.id.tabLayout_instruments);
tabLayout.setupWithViewPager(viewPager, false);
return view;
}
//Add Fragments to Tabs
private void tabsToViewPager(ViewPager viewPager) {
Adapter adapter = new Adapter(getChildFragmentManager());
//Brass Fragments
adapter.addFragment(new Inst_Br_Frag1(), "Name1");
adapter.addFragment(new Inst_Br_Frag2(), "Name2");
adapter.addFragment(new Inst_Br_Frag3(), "Name3");
adapter.addFragment(new Inst_Br_Frag4(), "Name4");
adapter.addFragment(new Inst_Br_Frag5(), "Name5");
adapter.addFragment(new Inst_Br_Frag6(), "Name6");
viewPager.setAdapter(adapter);
}
static class Adapter extends FragmentStatePagerAdapter {
//mFragmentList stores ChildFragments
private final List<Fragment> mFragmentList = new ArrayList<>();
//mFragmentTitleList stores the displayed name of each ChildFragment
private final List<String> mFragmentTitleList = new ArrayList<>();
Adapter(FragmentManager manager) {
super(manager);
}
// Return the Fragment associated with a specified position
#Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
// getCount() returns the number of views available
#Override
public int getCount() {
return mFragmentList.size();
}
void addFragment(Fragment fragment, String title) {
mFragmentList.add(fragment);
mFragmentTitleList.add(title);
}
//This method may be called by the ViewPager to obtain a title string to describe the specified page.
#Override
public CharSequence getPageTitle(int position) {
return mFragmentTitleList.get(position);
}
}
}
I've always worked with FragmentActivity and TabHost to add/remove/replace Fragment programmatically.
What I was using was:
public void addFragments(String tabName, Fragment fragment,
boolean animate, boolean add, Bundle bundle) {
currentSelectedTab = tabName;
if (add) {
hMapTabs.get(tabName).add(fragment);
}
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction ft = manager.beginTransaction();
if (animate) {
ft.setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left);
}
if (bundle!=null){
fragment.setArguments(bundle);
}
ft.replace(R.id.realtabcontent, fragment, tabName);
ft.commitAllowingStateLoss();
}
public void removeFragment() {
Fragment fragment = hMapTabs.get(currentSelectedTab).get(
hMapTabs.get(currentSelectedTab).size() - 2);
hMapTabs.get(currentSelectedTab).remove(
hMapTabs.get(currentSelectedTab).size() - 1);
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction ft = manager.beginTransaction();
ft.setCustomAnimations(R.anim.slide_in_left, R.anim.slide_out_right);
ft.replace(R.id.realtabcontent, fragment);
ft.commitAllowingStateLoss();
}
With that, everything works OK.
Now I'm trying to manage this Fragment's behavior on a page of my ViewPager.
I've been searching on StackOverFlow for three hours and I get confused everytime more and more. Tried with public functions on FragmentPagerAdapter for example.
And what only worked makes me a white blank screen on adding Fragments.
How would you do it?
Thanks in advance.
I found a workaround for my problem but I don't know if it's effective.
I'm defining a HashMap to keep my Fragments:
private HashMap<Integer, ArrayList<Fragment>> hMapTabs = new HashMap<Integer, ArrayList<Fragment>>();
then I initializate it and I add my first fragments of every position (in this case, the fragments are the same).
hMapTabs.put(0, new ArrayList<Fragment>());
hMapTabs.put(1, new ArrayList<Fragment>());
hMapTabs.put(2, new ArrayList<Fragment>());
hMapTabs.get(0).add(new PrimerFragment());
hMapTabs.get(1).add(new PrimerFragment());
hMapTabs.get(2).add(new PrimerFragment());
and I set my adapter to my ViewPager. This would be the FragmentAdapterPager:
public class CollectionPagerAdapter extends FragmentStatePagerAdapter {
final int NUM_ITEMS = 3; // number of tabs
FragmentManager fm;
HashMap<Integer, ArrayList<Fragment>> hMapTabs;
public CollectionPagerAdapter(FragmentManager fm, HashMap<Integer, ArrayList<Fragment>> hMapTabs) {
super(fm);
this.fm = fm;
this.hMapTabs = hMapTabs;
}
#Override
public Fragment getItem(int position) {
return hMapTabs.get(position).get(hMapTabs.get(position).size()-1);
}
#Override
public int getCount() {
return NUM_ITEMS;
}
#Override
public CharSequence getPageTitle(int position) {
String tabLabel = null;
switch (position) {
case 0:
tabLabel = "tab1";
break;
case 1:
tabLabel = "tab2";
break;
case 2:
tabLabel = "tab3";
break;
}
return tabLabel;
}
}
from every fragment, I can add or remove fragments with the functions:
public void addFragment(int position, Fragment frag) {
hMapTabs.get(position).add(frag);
mCollectionPagerAdapter = new CollectionPagerAdapter(
getSupportFragmentManager(), hMapTabs);
mViewPager.setAdapter(mCollectionPagerAdapter);
}
public void removeFragment(int position) {
hMapTabs.get(position).remove(
hMapTabs.get(position).size() - 1);
mCollectionPagerAdapter = new CollectionPagerAdapter(
getSupportFragmentManager(), hMapTabs);
mViewPager.setAdapter(mCollectionPagerAdapter);
}
#Override
public void onBackPressed() {
int position = mViewPager.getCurrentItem();
if (hMapTabs.get(position).size() <= 1) {
super.onBackPressed();
} else {
removeFragment(position);
}
}
but what I can't do is adding an Animation... how would I do it? :D
I am trying to create facebook like viewpager (swipable tabs and proper backstack) I can create swipable tabs but cant handle the proper back navigation. Bellow is my code
public class MainActivity extends FragmentActivity {
private ViewPager mPager;
// private SlidePagerAdapter mPagerAdapter;
private MyPagerAdapter mPagerAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/* Instantiate a ViewPager and a PagerAdapter. */
mPager = (ViewPager) findViewById(R.id.pager);
mPagerAdapter = new MyPagerAdapter(getSupportFragmentManager());
mPager.setAdapter(mPagerAdapter);
mPager.setOffscreenPageLimit(4);
}
#Override
public void onBackPressed() {
Fragment currentVisibleFragment = mPagerAdapter.getRegisteredFragment(mPager.getCurrentItem());
if (currentVisibleFragment != null && currentVisibleFragment.isVisible()) {
FragmentManager childFm = currentVisibleFragment.getChildFragmentManager();
System.out.println("============================================");
System.out.println("childFm.getBackStackEntryCount()=== " + childFm.getBackStackEntryCount());
System.out.println("============================================");
if (childFm.getBackStackEntryCount() > 0) {
childFm.popBackStack();
return;
}
}
super.onBackPressed();
}
}
Adapter of my class is as bellow
public class MyPagerAdapter extends SmartFragmentStatePagerAdapter {
private static int NUM_ITEMS = 3;
public MyPagerAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
}
// Returns total number of pages
#Override
public int getCount() {
return NUM_ITEMS;
}
// Returns the fragment to display for that page
#Override
public Fragment getItem(int position) {
switch (position) {
case 0: // Fragment # 0 - This will show FirstFragment
return new FragmentA();
case 1: // Fragment # 0 - This will show FirstFragment different title
return new FragmentB();
case 2: // Fragment # 1 - This will show SecondFragment
return new FragmentC();
default:
return null;
}
}
// Returns the page title for the top indicator
#Override
public CharSequence getPageTitle(int position) {
return "Page " + position;
}
}
here is the exteded adapter
public abstract class SmartFragmentStatePagerAdapter extends FragmentStatePagerAdapter {
// Sparse array to keep track of registered fragments in memory
private SparseArray<Fragment> registeredFragments = new SparseArray<Fragment>();
public SmartFragmentStatePagerAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
}
// Register the fragment when the item is instantiated
#Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment fragment = (Fragment) super.instantiateItem(container, position);
registeredFragments.put(position, fragment);
return fragment;
}
// Unregister when the item is inactive
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
registeredFragments.remove(position);
super.destroyItem(container, position, object);
}
// Returns the fragment for the position (if instantiated)
public Fragment getRegisteredFragment(int position) {
return registeredFragments.get(position);
}
}
and Fragments are as bellow
public class FragmentA extends Fragment {
public static final String TAG = "FragmentA";
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.first_fragment, container, false);
Button btn = (Button) view.findViewById(R.id.btn);
btn.setText(TAG);
btn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
FragmentTransaction trans = getChildFragmentManager().beginTransaction();
/*
* IMPORTANT: We use the "root frame" defined in
* "root_fragment.xml" as the reference to replace fragment
*/
trans.replace(R.id.framelayout_infragment_one, new FragmentA1());
/*
* IMPORTANT: The following lines allow us to add the fragment
* to the stack and return to it later, by pressing back
*/
trans.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
trans.addToBackStack(null);
trans.commit();
}
});
return view;
}
}
public class FragmentA1 extends Fragment {
public static final String TAG = "FragmentA1";
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.first_fragment, container, false);
view.setBackgroundColor(Color.RED);
Button btn = (Button) view.findViewById(R.id.btn);
btn.setText(TAG);
btn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
FragmentTransaction trans = getChildFragmentManager().beginTransaction();
/*
* IMPORTANT: We use the "root frame" defined in
* "root_fragment.xml" as the reference to replace fragment
*/
trans.replace(R.id.framelayout_infragment_one, new FragmentA2());
/*
* IMPORTANT: The following lines allow us to add the fragment
* to the stack and return to it later, by pressing back
*/
trans.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
trans.addToBackStack(null);
trans.commit();
}
});
return view;
}
}
//second inner fragment
public class FragmentA2 extends Fragment {
public static final String TAG = "FragmentA2";
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.second_fragment, container, false);
view.setBackgroundColor(Color.GRAY);
Button btn = (Button) view.findViewById(R.id.btn);
btn.setText(TAG);
btn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
FragmentTransaction trans = getFragmentManager().beginTransaction();
trans.replace(R.id.root_frame, new FragmentC());
trans.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
trans.addToBackStack(null);
trans.commit();
}
});
return view;
}
}
When I am going to frament A2 expected behaviour when user press back is I want to go to Frament A1 but I am going to Frament A. Fragment B,B1,B2 are same as A A1 A2 resp...
Please help
I managed it by maintaining stacks by myself
public static HashMap<String, Stack<Fragment>> mStacks;
mStacks = new HashMap<String, Stack<Fragment>>();
mStacks.put("TAB1", new Stack<Fragment>());
mStacks.put("TAB2", new Stack<Fragment>());
mStacks.put("TAB3", new Stack<Fragment>());
mStacks.put("TAB4", new Stack<Fragment>());
//when starting new fragment add that to stack like this
public void pushFragments(Fragment fragment) {
setSelectedPageN(pager.getCurrentItem());
mStacks.get(ApplicationConstants.CURRENT_TAB).push(fragment);
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction ft = manager.beginTransaction();
if (ApplicationConstants.CURRENT_TAB.equals("TAB1")) {
ft.replace(R.id.container_feed, fragment);
} else if (ApplicationConstants.CURRENT_TAB.equals("TAB2")) {
ft.replace(R.id.container_chart, fragment);
} else if (ApplicationConstants.CURRENT_TAB.equals("TAB3")) {
ft.replace(R.id.container_explore, fragment);
} else if (ApplicationConstants.CURRENT_TAB.equals("TAB4")) {
ft.replace(R.id.container_profile, fragment);
}
ft.commit();
}
//When you want to finish
public void popFragments() {
/*
* Select the second last fragment in current tab's stack.. which will
* be shown after the fragment transaction given below
*/
setSelectedPageN(pager.getCurrentItem());
Fragment fragment = mStacks.get(ApplicationConstants.CURRENT_TAB).elementAt(mStacks.get(ApplicationConstants.CURRENT_TAB).size() - 2);
if (fragment instanceof ProfileContainerFragment) {
fragment = new ProfileFragment();
} else if (fragment instanceof FeedNewUserGuideline && !isShowFeedTutorial) {
fragment = new FeedFragment();
}
/* pop current fragment from stack.. */
mStacks.get(ApplicationConstants.CURRENT_TAB).pop();
/*
* We have the target fragment in hand.. Just show it.. Show a standard
* navigation animation
*/
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction ft = manager.beginTransaction();
ft.setCustomAnimations(R.anim.abc_fade_in, R.anim.abc_fade_out);
if (ApplicationConstants.CURRENT_TAB.equals(ApplicationConstants.TAB_FEED)) {
ft.replace(R.id.container_feed, fragment);
} else if (ApplicationConstants.CURRENT_TAB.equals(ApplicationConstants.TAB_CHART)) {
ft.replace(R.id.container_chart, fragment);
} else if (ApplicationConstants.CURRENT_TAB.equals(ApplicationConstants.TAB_EXPLORE)) {
ft.replace(R.id.container_explore, fragment);
} else if (ApplicationConstants.CURRENT_TAB.equals(ApplicationConstants.TAB_PROFILE)) {
ft.replace(R.id.container_profile, fragment);
}
ft.commit();
}
//When user back press
#Override
public void onBackPressed() {
try {
if (((BaseFragment) mStacks.get(ApplicationConstants.CURRENT_TAB).lastElement()).onBackPressed() == false) {
switch (pager.getCurrentItem()) {
case KeyConstants.POSITION_ONE_FEED:
if (mStacks.get(ApplicationConstants.TAB_FEED).size() == 1) {
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
this.finish();
// super.onBackPressed(); // or call finish..
} else {
popFragments();
}
break;
case KeyConstants.POSITION_TWO_CHART:
if (mStacks.get(ApplicationConstants.TAB_CHART).size() == 1) {
pager.setCurrentItem(KeyConstants.POSITION_ONE_FEED);
} else {
popFragments();
}
break;
case KeyConstants.POSITION_THREE_EXPLORE:
if (mStacks.get(ApplicationConstants.TAB_EXPLORE).size() == 1) {
pager.setCurrentItem(KeyConstants.POSITION_TWO_CHART);
} else {
popFragments();
}
break;
case KeyConstants.POSITION_FOUR_PROFILE:
if (mStacks.get(ApplicationConstants.TAB_PROFILE).size() == 1) {
pager.setCurrentItem(KeyConstants.POSITION_THREE_EXPLORE);
} else {
popFragments();
}
break;
default:
break;
}
} else {
// do nothing.. fragment already handled back button press.
}
} catch (Exception e) {
e.printStackTrace();
}
}
I want to display another Fragment when the phone isn't connected to a WiFi network. Normally I'm displaying MainFragment, when no connection is available ErrorFragment.
I'm using mWifi.isConnected() to check if there is a connection.
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
if (mWifi.isConnected()) {
new PostTask(1).execute();
} else {
MainFragment.firstPageListener.onSwitchToNextFragment();
}
}
This is my code (inside MainFragment) to switch to the ErrorFragment, but it's giving me
11-23 20:57:29.588: E/AndroidRuntime(4025): java.lang.IllegalStateException: Recursive entry to executePendingTransactions
This is in my MainActivity (I'm using a ViewPager):
public class SectionsPagerAdapter extends FragmentPagerAdapter {
private final class FirstPageListener implements FirstPageFragmentListener {
public void onSwitchToNextFragment() {
mFragmentManager.beginTransaction().remove(mFragmentAtPos0).commit();
if (mFragmentAtPos0 instanceof MainFragment) {
mFragmentAtPos0 = new ErrorFragment(listener);
} else { // Instance of NextFragment
mFragmentAtPos0 = new MainFragment(listener);
}
notifyDataSetChanged();
}
}
private String[] titles = { "SEARCH", "LIST" };
private final FragmentManager mFragmentManager;
public Fragment mFragmentAtPos0;
private Context context;
FirstPageListener listener = new FirstPageListener();
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
mFragmentManager = fm;
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0: // Fragment # 0
if (mFragmentAtPos0 == null) {
mFragmentAtPos0 = new MainFragment(listener);
}
return mFragmentAtPos0;
case 1: // Fragment # 1
return new ListFragment();
}
return null;
}
#Override
public int getCount() {
return titles.length;
}
#Override
public int getItemPosition(Object object) {
if (object instanceof MainFragment && mFragmentAtPos0 instanceof ErrorFragment) {
return POSITION_NONE;
}
if (object instanceof MainFragment && mFragmentAtPos0 instanceof MainFragment) {
return POSITION_NONE;
}
return POSITION_UNCHANGED;
}
#Override
public CharSequence getPageTitle(int position) {
return titles[position];
}
}
public interface MainFragmentListener {
void onSwitchToNextFragment();
}
I tried to change Fragments with:
FragmentManager fragmentManager2 = getFragmentManager();
FragmentTransaction fragmentTransaction2 = fragmentManager2.beginTransaction();
ErrorFragment fragment2 = new ErrorFragment();
fragmentTransaction2.addToBackStack("xyz");
fragmentTransaction2.hide(MainFragment.this);
fragmentTransaction2.add(android.R.id.content, fragment2);
fragmentTransaction2.commit();
But when I swipe to the other Tab, the Fragments are overlapping... What should do? Thanks!
(The thumbs down is the ErrorFragment, the Button and On/Off Switch, is in ListFragment)
Try to remove
fragmentTransaction2.hide(MainFragment.this);
and change
fragmentTransaction2.add(android.R.id.content, fragment2);
to
fragmentTransaction2.replace(android.R.id.content, fragment2);
I'm presented with this unpleasant message on this code
public static HelpDetailsFragment newInstance(int index)
{
HelpDetailsFragment detailFragment = new HelpDetailsFragment();
Bundle bundleArgs = new Bundle();
bundleArgs.putInt("index", index);
detailFragment.setArguments(bundleArgs);
return detailFragment;
} // newInstance()
public int getCurrentIndex()
{
return getArguments().getInt("index", 0);
}
I'm using this code here:
HelpDetailsFragment detailFragment = (HelpDetailsFragment) getFragmentManager()
.findFragmentById(R.id.helpDetailsFrame);
if((detailFragment == null) || (detailFragment.getCurrentIndex() != index))
{
detailFragment = HelpDetailsFragment.newInstance(index);
Log.i(TAG, "HelpListFragment Create and replace details fragment for item:"+index);
FragmentTransaction fragTrans = getFragmentManager().beginTransaction();
fragTrans.replace(R.id.helpDetailsFrame, detailFragment);
fragTrans.commit();
}
What em I missing here??