I have an Actionbar app with fragments and a TabFragment extends Fragment class, where I customize the functionality of my fragments.
I want to be able to control what the back button does.
#Overriding onBackPressed()
won't work because I am not in an Activity,
nor will
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if ((keyCode == KeyEvent.KEYCODE_BACK)) {
//my code here
}
return super.onKeyDown(keyCode, event);
}
My goal is to hide some specific Views when I press back based on true/false value of a boolean variable. Any suggestions on how I might be able to manipulate this functionality? Thanks!
I had the same problem as you, but I realized that you had to deal with the back button in the activity where you are running your fragments from. You need to override the onBackPressed() in the activity code, not inside the fragment code. Then you can check to see which fragment is visible and do what you want accordingly.
This code is in my activity:
#Override
public void onBackPressed()
{
try
{
final LiveWorkFragment liveFragment = (LiveWorkFragment)getFragmentManager().findFragmentByTag("live_work");//LiveWorkFragment is a fragment
final NonLiveWorkFragment nonLiveFragment = (NonLiveWorkFragment)getFragmentManager().findFragmentByTag("non_live");//NonLiveWorkFragment is a fragment
final SignatureFragment signatureFragment = (SignatureFragment)getFragmentManager().findFragmentByTag("signature");//this is a Fragment too
if(liveFragment == null && nonLiveFragment == null && signatureFragment == null)
{
super.onBackPressed();
}
if(liveFragment != null)
{
if (liveFragment.isVisible())
{
//do what you want
}
}
}
}
Related
I am trying to implement back navigation through my fragments which are called in specific order: A->B->C and by going back with hardware button I would like them to remain order.
I am using fragmenttransaction.replace in order to switch fragment with no addToBackStack because it made my ActionBarMenu to misbehave.
Problem is that when I am on fragment C back button is going back directly to A. I found out that it is because click event is executed twice I am going to B and directly to A.
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
setOnBackButtonPresed();
}
private void setOnBackButtonPresed() {
getView().setFocusableInTouchMode(true);
getView().requestFocus();
getView().setOnKeyListener( new View.OnKeyListener()
{
#Override
public boolean onKey( View v, int keyCode, KeyEvent event )
{
if( keyCode == KeyEvent.KEYCODE_BACK )
{
goBackToDays();
return false;
}
return false;
}
} );
}
private void goBackToDays() {
Log.e("fragmentC", "executing on back action")
}
logcat result:
03-15 08:37:17.353 21245-21245/com.test E/fragmentC: executing on back action
03-15 08:37:17.390 21245-21245/com.test E/fragmentC: executing on back action
Can anyone give me a hint how I can avoide twice button events?
I think "click event is executed twice" because you call both event ACTION_DOWN and ACTION_UP. Try this
#Override
public boolean onKey( View v, int keyCode, KeyEvent event )
{
if( keyCode == KeyEvent.KEYCODE_BACK && event.getAction()== KeyEvent.ACTION_DOWN)
{
goBackToDays();
return false;
}
return false;
}
2 things:
Even though you're replacing fragments, the old OnKeyListener stays there (and get's fired up later on). Try removing the old OnKeyListener on switching fragments.
Just as S-lightning pointed out, you need to bare in mind that there are two actions associated with a key event (KeyEvent.ACTION_DOWN and KeyEvent.ACTION_UP).
You can do two things
"it made my ActionBarMenu to misbehave." FIX this issue.
Override onBackPressed() on your Activity and find find out your current loaded fragment and replace with whichever you want.
Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.your_view_container);
if (fragment instanceof FragmentThree) {
//replace with your fragment ie. FragmentTwo
} else if (fragment instanceof FragmentTwo) {
//replace with your fragment ie. FragmentOne
}
Return true if you want to "absorb" the key event and stop it from propagating up to the Activity, which has its own onBackPressed() implementation.
if( keyCode == KeyEvent.KEYCODE_BACK )
{
goBackToDays();
return true; // <-- should be TRUE, not FALSE
}
return false;
Override the onBackPressed() method in hosting activity.
do like this.
private void replaceFragment (Fragment fragment){
String backStateName = fragment.getClass().getName();
FragmentManager manager = getSupportFragmentManager();
boolean fragmentPopped = manager.popBackStackImmediate(backStateName, 0);
if (!fragmentPopped){ //fragment not in back stack, create it.
FragmentTransaction ft = manager.beginTransaction();
ft.replace(R.id.content_frame, fragment);
ft.addToBackStack(backStateName);
ft.commit();
}
}
.
.
#Override
public void onBackPressed(){
if (getSupportFragmentManager().getBackStackEntryCount() == 1){
finish();
}
else {
super.onBackPressed();
}
}
Here is the well explained answer. link
In my main Activity I've set up a interface CentreKeyPress, and I have 4 Fragments in a ViewPager, and a few of them implement this, a few don't. The interface has an onBack method, for when the back button is pressed. Here's my current code
#Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
ViewPager pager = (ViewPager)findViewById(R.id.contact_view_pager);
List<Fragment> frags = adapter.getFragments();
try {
((CentreKeyPress) frags.get(pager.getCurrentItem())).onBack();
return true;
} catch (Exception e) {
e.printStackTrace();
}
}
return super.onKeyUp(keyCode, event);
}
Is a try/catch loop the best way to check if a Fragment implements the interface, or is there some kind of method that I can use to check if it implements it? Or, alternatively, could my Fragment handle onKeyUp themselves?
Try to use keyword INSTANCEOF and check if fragments are instance of interface
you can check this to: use of "Instance of" in java
Check whether fragment is a instanceof the given fragment
if(frags.get(pager.getCurrentItem()) instanceof CentreKeyPress){
//fragment implements CentreKeyPress
}
which function will be called after popBackStack is called?
I mean, when a certain fragment becomes active after calling popBackStack, which function will be called?
I did debug but onResume is called after certain activity is done something like clicking button etc.
But I need to call a function when fragment becomes active by getting called popBackStack
I just had the same question and tried to find out which default method is called when a fragment becomes active after calling popBackStack, but couldn't find any default methods called(here I mean onResume, onAttached, etc by default methods).
Hence I worked it out by calling the active fragment's method explicitly just after calling popBackStack.
For example, suppose we have two fragments A and B in the same activity and have clicked back button of the Android device on fragment A.
//fragment A
#Override
public void onResume() {
super.onResume();
getView().setFocusableInTouchMode(true);
getView().requestFocus();
getView().setOnKeyListener(new View.OnKeyListener() {
#Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK) {
// handle back button
FragmentManager fm = getFragmentManager();
fm.popBackStack();
//call fragment B.setBackButtonLister method
B fragment = (B)getFragmentManager().findFragmentByTag(B.TAG);
if (fragment != null){
fragment.setBackButtonListener();
}
return true;
}
return false;
}
});
}
This way, you can call any method of fragment B after you get the handle of B.
Hope this will help you, Cheers!
I want to go back to the last fragment in the back stack, so I want to make the back button popback the stack. Should I do this? and if so, should I override onBackPressed() or onKeyDown()?
#Override
public void onBackPressed()
{
Intent intent = new Intent(this,ABC.class);
startActivity(intent);
}
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK ) {
// do something on back.
return true;
}
return super.onKeyDown(keyCode, event);
}
My fragments aren't being added to the back stack properly for some reason
I am using this to try to go back to the previous fragment, but the order is acting strange. What exactly should I do to make the order proper?
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft){
if(teamsFrag !=null)
{
if(manage.getBackStackEntryCount() > 0)
manage.popBackStack(manage.getBackStackEntryAt(manage.getBackStackEntryCount()-1).getName(), FragmentManager.POP_BACK_STACK_INCLUSIVE);
//ft.detach(dataFrag);
}
Short answer? No.
Long answer? If you have to ask, No.
You should set your fragments up using the fragment manager so that the back button does what you want. You shouldn't override the back button instead of implementing your stack correctly.
I want to go back to the last fragment in the back stack, so I want to make the back button popback the stack.
This is the default behavior when you use FragmentTransaction#addToBackStack() while adding new Fragments with the FragmentManager.
I am having two fragments Frag A and Frag B which are rendered using view pager .
If user has swiped from A to B then presses back button(when in B) then user should go to A instead of coming out of view pager . How can we achieve this ?
Adding transaction to backstack does not seem to help .
Thanks
You have to override the onKeyDown() method in the Activity.
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
myViewPager.setCurrentItem(0, true);
return true;
} else {
return super.onKeyDown(keyCode, event);
}
}
This will capture the "back" button press event and send the user to the first item in the ViewPager.
There is also ViewPager#getCurrentItem() which can be used to go back only if the user swiped. An implementation like this:
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && myViewPager.getCurrentItem() == 1) {
myViewPager.setCurrentItem(0, true);
return true;
} else {
return super.onKeyDown(keyCode, event);
}
}
would send the user back to the previous page only if the user was on the next page. Else, it will register the "back" normally and the user will exit as expected.
You may want the case in which the user goes back to the previous page (assuming you have more than two pages). In which case, you want to implement the ViewPager.OnPageChangeListener() and save the position every time onPageSelected(int position) is called. If you implement them in a stack, then you can pop them off every time the user presses "back". Once the stack is empty, exit the app.
EDIT
As correctly stated in the comments by Jade Byfield, a slightly easier way to do this would be to use onBackPressed() in the Activity. This will only work in API levels 5+.
#Override
public void onBackPressed() {
if(i_dont_want_to_leave) {
myViewPager.setCurrentItem(0, true);
} else {
super.onBackPressed(); // This will pop the Activity from the stack.
}
}
On the Android Docs page
https://developer.android.com/training/animation/screen-slide.html#viewpager
I found an example of handling ViewPager sliding and there's a method
#Override
public void onBackPressed() {
if (mPager.getCurrentItem() == 0) {
super.onBackPressed();
}
else {
mPager.setCurrentItem(mPager.getCurrentItem() - 1);
}
}
This selects a previous page or exits the current activity.
I think a better approach would be to delegate the back key handling to the respective fragments. I have used a CustomFragment which supports a method to handle the back key. All the Fragments will be extending from this CustomFragment.
public abstract class BackKeyHandlingFragment extends Fragment {
public abstract boolean handleBackKey();
}
Activity can delegate the backKey processing to current Fragment. Fragments can perform required actions in their respective implementation of handleBackKey method. The method can return true to tell activity not to process the back key. To go ahead with default back key action at Activity level, the method can return false.
public void onBackPressed() {
BackKeyHandlingFragment fragment = (BackKeyHandlingFragment) mSectionsPagerAdapter.getItem(mViewPager.getCurrentItem());
// Fragment should return boolean according to app requirements after processing back key
if (!fragment.handleBackKey()) {
super.onBackPressed();
}
}