I have a Fragment which contains viewpager.
inside ViewPager I have 3 more Fragments, Fragment-A,Fragment-B, and Fragment-C.
Inside Fragment A I have a Button, in Button onClick() I want to change the current item to Fragment C.
How can I achieve it? Please help
If button is not in main fragment, you'll have to define an interface to communicate between your main fragment and sub fragments i.e fragment A B C.
public interface GoToNextFragment {
void onGoToFragment(int index);
}
Your MainFragmet will have to implement this interface and the method that goes with it :
public class MainFragment extends Fragment implements GoToNextFragment {
//Your regular methods...
#Override
public void onGoToFragment(index) {
if (myAdapter != null) {
myAdapter.setCurrentItem(index);
}
}
Still in your MainFragment, set the interface on your fragments :
fragment1.setInterface(this);
fragment2.setInterface(this);
In your Fragments, add the setInterface method :
private GoToNextFragment mInterface;
public void setInterface(GoToNextFragment i) {
mInterface = i;
}
And finally in fragment a, trigger the effect with :
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (mInterface != null) {
mInterface.onGoToFragment(2);
}
});
In your clickHandler add this method viewpager.setCurrentItem(int index)
viewpager.postDelayed(new Runnable() {
#Override
public void run() {
viewpager.setCurrentItem(2);
}
}, 100);
Here 2 is your Fragment C index.
Update
No need to create object of viewpager in Fragment A.
Just create one interface that extend in your Activity or Fragment which contain ViewPager and implement it into Fragment A.
I am using Tabbed Activity of Android Studio.
I'm moving between the pages swiping but i added 2 views to move next and previous by onclick method but it doesn't work to go back only to go next.
nextAbitudini.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//it works
mViewPager.setCurrentItem(getArguments().getInt(ARG_SECTION_NUMBER));
}
});
backAbitudini.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//it doesn't work
mViewPager.setCurrentItem(getArguments().getInt(ARG_SECTION_NUMBER)-1);
}
});
I'm using FragmentPagerAdapter.
It works swiping back.
I put onClick methods inside onCreateview.
Refering to the Tabbed Activity, take a look at the section number as the fragment is initialized. (sectionNumber = position+1).
#Override
public Fragment getItem(int position) {
// getItem is called to instantiate the fragment for the given page.
// Return a PlaceholderFragment (defined as a static inner class below).
return PlaceholderFragment.newInstance(position + 1);
}
Therefore, ARG_SECTION_NUMBER-1 refers to the position of the current fragment, ARG_SECTION_NUMBER-2 to the previous, and ARG_SECTION_NUMBER to the next.
Consequently, your code should be like this:
nextAbitudini.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//it works
mViewPager.setCurrentItem(getArguments().getInt(ARG_SECTION_NUMBER));
}
});
backAbitudini.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//it doesn't work
mViewPager.setCurrentItem(getArguments().getInt(ARG_SECTION_NUMBER)-2);
}
});
#Override
public void onBackPressed() {
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
FragmentManager.BackStackEntry bSE = getSupportFragmentManager().getBackStackEntryAt(getSupportFragmentManager().getBackStackEntryCount() - 1);
Fragment frag = getSupportFragmentManager().findFragmentByTag(bSE.getName());
if (frag instanceof BackButtonBlocker)
{
BackButtonBlocker callback = (BackButtonBlocker) frag;
callback.onBackPressed();
}
else {
getSupportFragmentManager().popBackStack();
}
} else {
super.onBackPressed();
}
}
BackButtonBlocker interface is for callback. my fragment implements BackButtonBlocker but sometimes onBackPressed not occurs (onKeyUp as well).
when I open navigation drawer, onBackPressed and full logic works exactly.
why should activity lose focus?
android.support.v4.app.Fragment
public interface BackButtonBlocker{ void onBackPressed();}
take out super.onBackPressed(); from else{}
What I have done is that, I have not implemented any interface to handle back pressed see below.
#Override
public void onBackPressed() {
if (getDrawerLayout().isDrawerOpen(GravityCompat.START)) {
closeLeftMenu();
}
else {
if (getSupportFragmentManager().getBackStackEntryCount() > 1) {
super.onBackPressed();
} else {
finish(); // Means it is home and you can exit it from here.
}
}}
When drawer is open just close it then use your code.
I fixed this issue by adding setFocusableInTouchMode(true); requestFocus(); on Mainactivity's container view
I want to return back to MainActivity on clicking back button from each fragment and destroy Activity after returning back to the MainActivity.
I have tried something but it is continuously calling the fragment but not destroying it.
#Override
public void onBackPressed() {
startActivity(new Intent(this,MainActivity.class));
finish();
}
Do something like this in your MainActivity:
#Override
public void onBackPressed(){
Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.frameLayout);
if (fragment instanceof YourFragment || fragment instanceof YourOtherFragment) {
getSupportFragmentManager().beginTransaction().replace(R.id.frameLayout, new MainScreenFragment()).commit();
}else {
super.onBackPressed();
}
}
Add this to the Mainactivity
#Override
public void onBackPressed() {
if (getFragmentManager().getBackStackEntryCount() == 0) {
this.finish();
} else {
getFragmentManager().popBackStack();
}
}
I have a tabbed Actionbar/viewpager layout with three tabs say A, B, and C. In tab C tab(fragment),I am adding another fragment say fragment D. with
DFragment f= new DFragment();
ft.add(android.R.id.content, f, "");
ft.remove(CFragment.this);
ft.addToBackStack(null);
ft.commit();
I modify actionbar in DFragment's onResume to add up button:
ActionBar ab = getActivity().getActionBar();
ab.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
ab.setDisplayHomeAsUpEnabled(true);
ab.setDisplayShowHomeEnabled(true);
Now in DFragment, when I press hardware(phone) Back button, I return to the original Tabbed(ABC) layout with CFragment selected. How can I achieve this functionality with actionbar up button?
Implement OnBackStackChangedListener and add this code to your Fragment Activity.
#Override
public void onCreate(Bundle savedInstanceState) {
//Listen for changes in the back stack
getSupportFragmentManager().addOnBackStackChangedListener(this);
//Handle when activity is recreated like on orientation Change
shouldDisplayHomeUp();
}
#Override
public void onBackStackChanged() {
shouldDisplayHomeUp();
}
public void shouldDisplayHomeUp(){
//Enable Up button only if there are entries in the back stack
boolean canGoBack = getSupportFragmentManager().getBackStackEntryCount()>0;
getSupportActionBar().setDisplayHomeAsUpEnabled(canGoBack);
}
#Override
public boolean onSupportNavigateUp() {
//This method is called when the up button is pressed. Just the pop back stack.
getSupportFragmentManager().popBackStack();
return true;
}
I got it. just override onOptionsItemSelected in hosting activity and popup the backstack, e.g.
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home: {
FragmentManager fm = getSupportFragmentManager();
if (fm.getBackStackEntryCount() > 0) {
fm.popBackStack();
return true;
}
break;
}
}
return super.onOptionsItemSelected(item);
}
Call getActionBar().setDisplayHomeAsUpEnabled(boolean); and getActionBar().setHomeButtonEnabled(boolean); in onBackStackChanged() as explained in an answer below.
If you have one parent activity and want this up button to work as a back button, you can use this code:
add this to the onCreate in your main activity class
getSupportFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
#Override
public void onBackStackChanged() {
int stackHeight = getSupportFragmentManager().getBackStackEntryCount();
if (stackHeight > 0) { // if we have something on the stack (doesn't include the current shown fragment)
getSupportActionBar().setHomeButtonEnabled(true);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
} else {
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
getSupportActionBar().setHomeButtonEnabled(false);
}
}
});
and then add onOptionsItemSelected like so:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
getSupportFragmentManager().popBackStack();
return true;
....
}
I generally use this all the time and seems pretty legit
you can go back with up button like back button ;
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
super.onBackPressed();
return true;
}
return super.onOptionsItemSelected(item);
}
I used a combination of Roger Garzon Nieto's and sohailaziz's answers. My app has a single MainActivity, and fragments A, B, C that are loaded into it. My "home" fragment (A) implements OnBackStackChangedListener, and checks the size of the backStack; if it's less than one, then it hides the UP button. Fragments B and C always load the back button (in my design, B is launched from A, and C is launched from B). The MainActivity itself just pops the backstack on UP button tap, and has methods to show/hide the button, which the fragments call:
MainActivity:
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
// Respond to the action bar's Up/Home button
case android.R.id.home:
getSupportFragmentManager().popBackStack();
return true;
}
return super.onOptionsItemSelected(item);
}
public void showUpButton() { getSupportActionBar().setDisplayHomeAsUpEnabled(true); }
public void hideUpButton() { getSupportActionBar().setDisplayHomeAsUpEnabled(false); }
fragmentA (implements FragmentManager.OnBackStackChangedListener):
public void onCreate(Bundle savedinstanceSate) {
// listen to backstack changes
getActivity().getSupportFragmentManager().addOnBackStackChangedListener(this);
// other fragment init stuff
...
}
public void onBackStackChanged() {
// enable Up button only if there are entries on the backstack
if(getActivity().getSupportFragmentManager().getBackStackEntryCount() < 1) {
((MainActivity)getActivity()).hideUpButton();
}
}
fragmentB, fragmentC:
public void onCreate(Bundle savedinstanceSate) {
// show the UP button
((MainActivity)getActivity()).showUpButton();
// other fragment init stuff
...
}
I know this question is old, but may be someone (like me) also needs it.
If your Activity extends AppCompatActivity, you can use a simpler (two-step) solution:
1 - Whenever you add a non-home fragment just show the up button, right after commiting the fragment transaction. Like this:
// ... add a fragment
// Commit the transaction
transaction.commit();
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
2 - Then when UP button is pressed, you hide it.
#Override
public boolean onSupportNavigateUp() {
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
return true;
}
That's it.
This worked for me. Override onSupportNavigateUp and onBackPressed, for example (code in Kotlin);
override fun onBackPressed() {
val count = supportFragmentManager.backStackEntryCount
if (count == 0) {
super.onBackPressed()
} else {
supportFragmentManager.popBackStack()
}
}
override fun onSupportNavigateUp(): Boolean {
super.onSupportNavigateUp()
onBackPressed()
return true
}
Now in the fragment, if you display the up arrow
activity.supportActionBar?.setDisplayHomeAsUpEnabled(true)
Clicking on it takes you back the previous activity.
Kotlin:
class MyActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
...
supportFragmentManager.addOnBackStackChangedListener { setupHomeAsUp() }
setupHomeAsUp()
}
private fun setupHomeAsUp() {
val shouldShow = 0 < supportFragmentManager.backStackEntryCount
supportActionBar?.setDisplayHomeAsUpEnabled(shouldShow)
}
override fun onSupportNavigateUp(): Boolean =
supportFragmentManager.popBackStack().run { true }
...
}
This is a very good and reliable solution: http://vinsol.com/blog/2014/10/01/handling-back-button-press-inside-fragments/
The guy has made an abstract fragment that handles the backPress behaviour and is switching between the active fragments using the strategy pattern.
For some of you there maybe a little drawback in the abstract class...
Shortly, the solution from the link goes like this:
// Abstract Fragment handling the back presses
public abstract class BackHandledFragment extends Fragment {
protected BackHandlerInterface backHandlerInterface;
public abstract String getTagText();
public abstract boolean onBackPressed();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(!(getActivity() instanceof BackHandlerInterface)) {
throw new ClassCastException("Hosting activity must implement BackHandlerInterface");
} else {
backHandlerInterface = (BackHandlerInterface) getActivity();
}
}
#Override
public void onStart() {
super.onStart();
// Mark this fragment as the selected Fragment.
backHandlerInterface.setSelectedFragment(this);
}
public interface BackHandlerInterface {
public void setSelectedFragment(BackHandledFragment backHandledFragment);
}
}
And usage in the activity:
// BASIC ACTIVITY CODE THAT LETS ITS FRAGMENT UTILIZE onBackPress EVENTS
// IN AN ADAPTIVE AND ORGANIZED PATTERN USING BackHandledFragment
public class TheActivity extends FragmentActivity implements BackHandlerInterface {
private BackHandledFragment selectedFragment;
#Override
public void onBackPressed() {
if(selectedFragment == null || !selectedFragment.onBackPressed()) {
// Selected fragment did not consume the back press event.
super.onBackPressed();
}
}
#Override
public void setSelectedFragment(BackHandledFragment selectedFragment) {
this.selectedFragment = selectedFragment;
}
}
If you want to go back to your previous activity if this activity has an empty stack of fragments:
This could be useful if you have a MainActivity and you are navigating to e.g. a SettingsActivity with nested prefernceScreens. NavigateUp will pop fragments until you can finish the SettingsActivity to go back to parentActivity/root.
/**
* On actionbar up-button popping fragments from stack until it is empty.
* #return true if fragment popped or returned to parent activity successfully.
*/
#Override
public boolean onSupportNavigateUp() {
//Pop back stack if the up button is pressed.
boolean canGoBack = getSupportFragmentManager().getBackStackEntryCount()>0;
if (canGoBack) {
getSupportFragmentManager().popBackStack();
} else {
finish();
return super.onSupportNavigateUp();
}
return true;
}
Note: setDisplayHomeAsUpEnabled(true); in fragment activities onCreate()