I have a fragment that's in an AAR, and the main activity that holds this fragment is in another APK depending on this AAR.
I could override the handleKeyDown() in the activity, but is there any way that I can directly override/handle the keyDown in the fragment since there're multiple fragments for this activity.
p.s. I need to capture all sorts of keyevent e.g. up, down, left & right, not only back button.
Also I tried to implement KeyEvent.Callback but it's not catching any keyevent when I navigate thru UI.
Step1: Create a custom interface, let's say KeyEventListener
public interface MyKeyEventListener {
boolean onKeyDown(int keyCode, KeyEvent event);
}
Step2: Add field currentFragment in Activity, which will be updated whenever you switch fragment. Basically it will hold the currently visible fragment
Fragment currentFragment;
currentFragment = here getCurrentFragment() etc;
Step3: Implement MyKeyEventListener in your fragments. You can skip interface implementation in any fragment
public class Fragment1 implements MyKeyEventListener {
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
//do whatever you want in onKeyDown
}
}
Step4: Override onKeyDown in your Activity
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if(currentFragment != null && currentFragment instanceof MyKeyEventListener) {
((MyKeyEventListener) currentFragment).onKeyDown(keyCode, event);
return true;
}
return super.onKeyDown(keyCode, event);
}
Related
I have multiple fragments and I can switch between them, my problem is on how can I execute a method in a fragment before it goes to backstack.
If I execute some method in fragment's OnPause() or OnStop() my activity is closing with all fragments instantly. The code to switch from one fragment to another is:
public void switchFrgFromFrg(Fragment fragment, String tag, boolean isAddedToBackStack, int idContainer) {
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
fragmentTransaction.replace(idContainer, fragment, tag);
if (isAddedToBackStack) {
fragmentTransaction.addToBackStack(tag);
}
fragmentTransaction.commit();
}
Any help is apreciated.
Your fragment onResume() and onPause() will be called only when the Activity onResume() or onPause() that holds it is called. They are tightly coupled to the Activity, that's why your fragment is closing. I sugest you ti implement a back key listener as:
private void doBackActionListener(View view){
view.setFocusableInTouchMode(true);
view.requestFocus();
view.setOnKeyListener(new View.OnKeyListener() {
#Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_DOWN) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
//execute code
//then do standart go back action
getActivity().onBackPressed();
return true;
}
}
return false;
}
});
}
You will cal this in your onCreateView() and pass inflated view as parameter.
how can I execute a method in a fragment before it goes to backstack
When you fragment is visible you can execute as many methods as you want
If I execute some method in fragment's OnPause() or OnStop() my activity is closing with all fragments instantly.
That's because some Exception is arising in your code. It is better to show your console (Log messages) in your question.
I am using Fragment A,Fragment B .. and so on. i want to navigate back to the previous Fragment, from the current Fragment.
I want to use Back Button in Mobile to get back navigation.
How can i do this ? OR i have to make Back button in layout xml.
i tried below code,
fTransaction.add(R.id.container, nF).addToBackStack(null).commit();
when i pressed Back Button in Mobile , it restarts the App.
To go back to previous fragment using phone's back button you should override onKeyDown() mehtod.
#Override
public boolean onKeyDown(int keyCode, KeyEvent event)
{
if(keyCode == KeyEvent.KEYCODE_BACK)
{
getFragmentManager().popBackStack();
return true;
}
return false;
}
When replacing a fragment use replace instead of add and then addToBackStack:
fTransaction.replace(R.id.container, nF).addToBackStack(null).commit();
Try this:
fTransaction.addToBackStack(null).add(R.id.container, nF).commit();
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
}
}
}
}
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
}
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();
}
}