I have project with navigation drawer with fragment, with 5 menu, the problem is when i go to menu 4 and the i press the back button the app closed, but i need the app back to first menu which is all the menu in fragment.
This is code for Main Activity (Navigation Drawer)
public class MainActivity extends AppCompatActivity{
DrawerLayout mDrawerLayout;
NavigationView mNavigationView;
FragmentManager mFragmentManager;
FragmentTransaction mFragmentTransaction;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/**
*Setup the DrawerLayout and NavigationView
*/
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawerLayout);
mNavigationView = (NavigationView) findViewById(R.id.shitstuff) ;
/**
* Lets inflate the very first fragment
* Here , we are inflating the TabFragment as the first Fragment
*/
mFragmentManager = getSupportFragmentManager();
mFragmentTransaction = mFragmentManager.beginTransaction();
mFragmentTransaction.replace(R.id.containerView,new Recommendation()).commit();
/**
* Setup click events on the Navigation View Items.
*/
mNavigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(MenuItem menuItem) {
mDrawerLayout.closeDrawers();
if (menuItem.getItemId() == R.id.nav_item_lux_level_recomen) {
FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.containerView,new Recommendation()).commit();
}
if (menuItem.getItemId() == R.id.nav_item_room_index_calc) {
FragmentTransaction xfragmentTransaction = mFragmentManager.beginTransaction();
xfragmentTransaction.replace(R.id.containerView,new RoomIndex()).commit();
}
if (menuItem.getItemId() == R.id.nav_item_utilization_factor_calc) {
FragmentTransaction xfragmentTransaction = mFragmentManager.beginTransaction();
xfragmentTransaction.replace(R.id.containerView,new UtilizationFactorCalculator()).commit();
}
if (menuItem.getItemId() == R.id.nav_item_conversions) {
FragmentTransaction xfragmentTransaction = mFragmentManager.beginTransaction();
xfragmentTransaction.replace(R.id.containerView,new Conversion()).commit();
}
if (menuItem.getItemId() == R.id.nav_item_lux) {
FragmentTransaction xfragmentTransaction = mFragmentManager.beginTransaction();
xfragmentTransaction.replace(R.id.containerView,new LuxSensor()).commit();
}
return false;
}
});
/**
* Setup Drawer Toggle of the Toolbar
*/
android.support.v7.widget.Toolbar toolbar = (android.support.v7.widget.Toolbar) findViewById(R.id.toolbar);
ActionBarDrawerToggle mDrawerToggle = new ActionBarDrawerToggle(this,mDrawerLayout, toolbar,R.string.app_name,
R.string.app_name);
mDrawerLayout.setDrawerListener(mDrawerToggle);
mDrawerToggle.syncState();
}
This one of the Menu (Fragment)
public class LuxSensor extends Fragment {
TextView textLIGHT_available, textLIGHT_reading;
FragmentManager mFragmentManager;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View x = inflater.inflate(R.layout.lux_sensor,null);
textLIGHT_reading
= (TextView)x.findViewById(R.id.LIGHT_reading);
SensorManager mySensorManager = (SensorManager)getActivity().getSystemService(Context.SENSOR_SERVICE);
Sensor LightSensor = mySensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
if(LightSensor != null){
mySensorManager.registerListener(
LightSensorListener,
LightSensor,
SensorManager.SENSOR_DELAY_NORMAL);
}else{
textLIGHT_available.setText("Sensor.TYPE_LIGHT NOT Available");
}
FragmentManager fm = getFragmentManager();
return x;
}
private final SensorEventListener LightSensorListener
= new SensorEventListener(){
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// TODO Auto-generated method stub
}
#Override
public void onSensorChanged(SensorEvent event) {
if(event.sensor.getType() == Sensor.TYPE_LIGHT){
textLIGHT_reading.setText(event.values[0]+" LUX");
}
}
};
}
I have tried solution in internet but it still closed
In fragment you should use something like this:
#Override
//Pressed return button - returns to the results menu
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){
//your code
return true;
}
return false;
}
});
}
onCreateView of fragment add this
Java
requireActivity().getOnBackPressedDispatcher().addCallback(activity, new OnBackPressedCallback(true) {
#Override
public void handleOnBackPressed() {
// in here you can do logic when backPress is clicked
}
});
Kotlin
requireActivity().onBackPressedDispatcher.addCallback(object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
// in here you can do logic when backPress is clicked
}
})
In main activity you need to override the following function
#Override
public void onBackPressed()
{
// code here to check what fragment you are on and handle that accordingly
super.onBackPressed(); // this exits the app.
}
Documentation is available here: https://developer.android.com/reference/android/app/Activity.html#onBackPressed()
In your MainActivity
#Override
public void onBackPressed()
{
FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.containerView,new Recommendation()).commit();
}
use this (in kotlin)
activity?.onBackPressedDispatcher?.addCallback(this, object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
// in here you can do logic when backPress is clicked
}
})
i think this is the most elegant way to do it
You can key press listener in android using setOnKeyListener(). And then, if you want to handle the back press, override the onKey method :
#Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK) {
// do your thing
}
}
Now the onBackPressed method is deprecated and we need to use this way (much simpler !):
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
activity?.onBackPressedDispatcher?.addCallback(this, object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
if(shouldInterceptBackPress()){
// in here you can do logic when backPress is clicked
}else{
isEnabled = false
activity?.onBackPressed()
}
}
})
}
You can found full explanation here
With this example it shows how to do when you are not sure that you need to consume the back press event
Related
I am working on a bottom navigation bar, but I am not getting perfectly bottom navigation bar.
My MainActivity class:
public class MainActivity extends AppCompatActivity {
private static final String SELECTED_ITEM = "selected_item";
private BottomNavigationView bottomNavigationView;
private Toolbar toolbar;
private MenuItem menuItemSelected;
private int mMenuItemSelected;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
bottomNavigationView = (BottomNavigationView) findViewById(R.id.bottom_navigation);
bottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
selectFragment(item);
return true;
}
});
//Always load first fragment as default
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.frameLayout, new AnnouncementFragment());
fragmentTransaction.commit();
if (savedInstanceState != null) {
mMenuItemSelected = savedInstanceState.getInt(SELECTED_ITEM, 0);
menuItemSelected = bottomNavigationView.getMenu().findItem(mMenuItemSelected);
} else {
menuItemSelected = bottomNavigationView.getMenu().getItem(0);
}
selectFragment(menuItemSelected);
}
private void selectFragment(MenuItem item) {
Fragment fragment = null;
Class fragmentClass;
switch (item.getItemId()) {
case R.id.action_announcement:
fragmentClass = AnnouncementFragment.class;
break;
case R.id.action_menu:
fragmentClass = MenuFragment.class;
break;
case R.id.action_menu_reports:
fragmentClass = ReportFragment.class;
break;
case R.id.action_setting:
fragmentClass = SettingFragment.class;
break;
default:
fragmentClass = AnnouncementFragment.class;
}
try {
fragment = (Fragment) fragmentClass.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction().replace(R.id.frameLayout, fragment).commit();
}
#Override
protected void onSaveInstanceState(Bundle outState) {
outState.putInt(SELECTED_ITEM, mMenuItemSelected);
super.onSaveInstanceState(outState);
}
And my back pressed also not working properly:
#Override
public void onBackPressed() {
MenuItem homeItem = bottomNavigationView.getMenu().getItem(0);
if (mMenuItemSelected != homeItem.getItemId()) {
selectFragment(homeItem);
} else {
super.onBackPressed();
}
}
How should I do that because bottom menu has uneven distribution on bar. How to properly maintain the menu space without uneven distribution.
Here I am attaching my result which I obtain on AVD
According to the guidelines for Material Design
On Android, the Back button does not navigate between bottom
navigation bar views.
EDIT: Material Design link no longer mentions back button behavior.
Pressing the back button you can quit the application, which is the default behavior, such as in Google Photo...
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.content, fragment);
// note: there is NOT a addToBackStack call
fragmentTransaction.commit();
...or lead the user to the home section and then, if pushed again, at the exit.
Personally I find this last pattern much better.
To get it without override onBackPressed you need to identify the home fragment and differentiate it from all the others
navigation = (BottomNavigationView) findViewById(R.id.navigation);
navigation.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.navigation_home:
viewFragment(new HomeFragment(), FRAGMENT_HOME);
return true;
case R.id.navigation_page_1:
viewFragment(new OneFragment(), FRAGMENT_OTHER);
return true;
case R.id.navigation_page_2:
viewFragment(new TwoFragment(), FRAGMENT_OTHER);
return true;
}
return false;
}
});
What you have to do now is write the viewfragment method that have to:
Know how many fragments there are in the stack before the commit
If the fragment is not "home type", save it to the stack before
the commit
Add an OnBackStackChangedListener that when the stack decreases,
(i.e. when I pressed back ), delete all the fragments that are
not "home type" (POP_BACK_STACK_INCLUSIVE) , bringing us to the home fragment
Below the full method with comments
private void viewFragment(Fragment fragment, String name){
final FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.content, fragment);
// 1. Know how many fragments there are in the stack
final int count = fragmentManager.getBackStackEntryCount();
// 2. If the fragment is **not** "home type", save it to the stack
if( name.equals( FRAGMENT_OTHER) ) {
fragmentTransaction.addToBackStack(name);
}
// Commit !
fragmentTransaction.commit();
// 3. After the commit, if the fragment is not an "home type" the back stack is changed, triggering the
// OnBackStackChanged callback
fragmentManager.addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
#Override
public void onBackStackChanged() {
// If the stack decreases it means I clicked the back button
if( fragmentManager.getBackStackEntryCount() <= count){
// pop all the fragment and remove the listener
fragmentManager.popBackStack(FRAGMENT_OTHER, POP_BACK_STACK_INCLUSIVE);
fragmentManager.removeOnBackStackChangedListener(this);
// set the home button selected
navigation.getMenu().getItem(0).setChecked(true);
}
}
});
}
Try this
#Override
public void onBackPressed() {
BottomNavigationView bottomNavigationView = (BottomNavigationView) findViewById(R.id.navigation);
int seletedItemId = bottomNavigationView.getSelectedItemId();
if (R.id.home != seletedItemId) {
setHomeItem(MainActivity.this);
} else {
super.onBackPressed();
}
}
public static void setHomeItem(Activity activity) {
BottomNavigationView bottomNavigationView = (BottomNavigationView)
activity.findViewById(R.id.navigation);
bottomNavigationView.setSelectedItemId(R.id.home);
}
#Override
public void onBackPressed() {
BottomNavigationView mBottomNavigationView = findViewById(R.id.navigation);
if (mBottomNavigationView.getSelectedItemId() == R.id.navigation_home)
{
super.onBackPressed();
finish();
}
else
{
mBottomNavigationView.setSelectedItemId(R.id.navigation_home);
}
}
This is maybe a little late but I think the best way to do it is as simple as this.
#Override
public void onBackPressed() {
if (mBottomNavigationView.getSelectedItemId() == R.id.action_home) {
super.onBackPressed();
} else {
mBottomNavigationView.setSelectedItemId(R.id.action_home);
}
}
I hope it helps and happy coding :)
onBackPressed did not worked for me. So this I used.
#Override
protected void onResume() {
super.onResume();
bottomNavigationView.getMenu().getItem(0).setChecked(true);
}
The best way is: when in home button the app is closed and when in another button back in home button.
Below I put my code :
first i'm load home button in navigation View :
private void loadFragment(Fragment fragment) {
Toast.makeText(this, "load", Toast.LENGTH_SHORT).show();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.frame_container, fragment, TAG_FRAGMENT);
transaction.commit();
}
and remember dont call addToBackStack() .
and then handle the situation by onBackPressed() :
#Override
public void onBackPressed() {
if (navigation.getSelectedItemId() == R.id.bottomAkhbar) {
super.onBackPressed();
} else {
navigation.setSelectedItemId(R.id.bottomAkhbar);
}
}
I had the same problem so I solved my problem using this method:
In my main activity, I have a bottom nav bar and a nav drawer, I need to sync items in my drawer and bottom nav:
I created a method for my main fragment and the others:
my main fragment replacer:
public void MainFragmentChanger(final Fragment fragment, final String TAG){
if (main_page_fragment != null){
fragmentTransaction = myFragmentManager.beginTransaction();
fragmentTransaction.remove(main_page_fragment).commit();
}
if (main_drawer.isDrawerOpen()){
main_drawer.closeDrawer();
}
new Handler().post(new Runnable() {
#Override
public void run() {
main_page_fragment = fragment;
main_page_fragment.setRetainInstance(true);
fragmentTransaction = myFragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.main_container, main_page_fragment,TAG);
fragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
fragmentTransaction.commitAllowingStateLoss();
}
});
}
and this is for my other fragment replacer:
public void changeBottomFragment(final Fragment fragment, final String TAG){
if (main_drawer.isDrawerOpen()){
main_drawer.closeDrawer();
}
new Handler().post(new Runnable() {
#Override
public void run() {
main_page_fragment = fragment;
main_page_fragment.setRetainInstance(true);
fragmentTransaction = myFragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.main_container, main_page_fragment);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
fragmentTransaction.commitAllowingStateLoss();
}
});
}
so after that, I need to sync items in both drawer and bar:
Note I use material navigation drawer by Mike Penz, and com.ashokvarma.bottomnavigation.BottomNavigationBar for nav bar.
here is the method for that purpose:
public void changeNavAndBarStats(String tag){
if (tag == "flash"){
bottomNavigationBar.selectTab(2,false);
main_drawer.setSelection(flashcards.getIdentifier(),false);
}else if (tag == "dic"){
bottomNavigationBar.selectTab(3,false);
main_drawer.setSelection(dictionary.getIdentifier(),false);
}else if (tag == "Home"){
bottomNavigationBar.selectTab(0,false);
main_drawer.setSelection(home.getIdentifier(),false);
}
}
So I call my fragments Like this:
MainFragmentChanger(new MainPageFragment(),"Home");
bottomNavigationBar.selectTab(0,false);
changeBottomFragment(new FlashCardFragment(),"flash");
bottomNavigationBar.selectTab(2,false);
changeBottomFragment(new TranslateFragment(),"dic");
bottomNavigationBar.selectTab(3,false);
At the end I call changeNavAndBarStatus in my fragment's onResume method:
((MainPageActivity)getContext()).changeNavAndBarStats("flash");
That's it! you are good to go!
Try this to achieve the following:
on back press:
from home fragment exit the app.
from other fragments goto home fragment.
//On Back Press if we are at a Fragment other than the Home Fragment it will navigate back to the
// Home Fragment. From Home Fragment it will exit the App.
#Override
public void onBackPressed() {
int backStackEntryCount = getSupportFragmentManager().getBackStackEntryCount();
if (backStackEntryCount == 0) {
super.onBackPressed();
} else {
goHome();
}
}
public void goHome() {
//Following code will set the icon of the bottom navigation to active
final BottomNavigationView mBottomNav = findViewById(R.id.nav_view);
MenuItem homeItem = mBottomNav.getMenu().getItem(0);
mBottomNav.setSelectedItemId(homeItem.getItemId());
getSupportFragmentManager().popBackStackImmediate();
//To delete all entries from back stack immediately one by one.
int backStackEntry = getSupportFragmentManager().getBackStackEntryCount();
for (int i = 0; i < backStackEntry; i++) {
getSupportFragmentManager().popBackStackImmediate();
}
//To navigate to the Home Fragment
final HomeFragment homeFragment = new HomeFragment();
FragmentTransaction myFragmentTransaction = getSupportFragmentManager().beginTransaction();
myFragmentTransaction.replace(R.id.nav_host_fragment, homeFragment, "HomeFrag Tag");
myFragmentTransaction.commit();
}
You can try this /
its worked for me
public class MainActivity extends BaseActivity {
private HomeFragment homeFragment = new HomeFragment();
private CartFragment cartFragment = new CartFragment();
private ProfileFragment profileFragment = new ProfileFragment();
private BottomNavigationView bottomNavigationView;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState == null){
setContentView(R.layout.activity_main);
bottomNavigationView = findViewById(R.id.bottom_nav);
bottomNavigationView.setSelectedItemId(R.id.btnHome);
FragmentTransaction homeFm = getSupportFragmentManager().beginTransaction();
homeFm.replace(R.id.fragment_container, homeFragment);
homeFm.commit();
setupView();
}
}
private void setupView() {
bottomNavigationView.setOnNavigationItemSelectedListener(item -> {
{
switch (item.getItemId()) {
case R.id.btnHome:
loadFragment(homeFragment);
return true;
case R.id.btnCart:
loadFragment(cartFragment);
return true;
case R.id.btnProfile:
loadFragment(profileFragment);
return true;
}
return false;
}
});
}
private void loadFragment(Fragment fragment) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fragment_container, fragment);
transaction.addToBackStack(null);
transaction.commit();
}
#Override
public void onBackPressed() {
if (bottomNavigationView.getSelectedItemId() == R.id.btnHome)
{
finish();
}
else
{
bottomNavigationView.setSelectedItemId(R.id.btnHome);
}
}}
Use addToBackStack Method when calling a fragment like this,
getSupportFragmentManager().beginTransaction().addToBackStack(null).add(R.id.content_home_nav,newFragment).commit();
Use this code in your onBackPressed Method
if (getSupportFragmentManager().getBackStackEntryCount() > 0 ){
getFragmentManager().popBackStack();
} else {
super.onBackPressed();
}
For your requirement you would be working with fragments on navigation for this you can use Tablayout with view pager and make bottom navigation.
<android.support.design.widget.TabLayout
android:id="#+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="60dp"></android.support.design.widget.TabLayout>
and then setup viewpager with tab layout and add icon to tablayout in your activity
tabLayout = (TabLayout) findViewById(R.id.tab_layout);
viewPager = (ViewPager) findViewById(R.id.controller_pager);
viewPager.setAdapter(new ViewPagerAdapter(getSupportFragmentManager()));
viewPager.setOffscreenPageLimit(4);
tabLayout.setupWithViewPager(viewPager);
tabLayout.getTabAt(0).setIcon(R.drawable.selector_home);
tabLayout.getTabAt(1).setIcon(R.drawable.selector_contact);
tabLayout.getTabAt(2).setIcon(R.drawable.selector_profile);
tabLayout.getTabAt(3).setIcon(R.drawable.selector_settings);
now handle all things on the click of tablayout and it will work fine
tabLayout.addOnTabSelectedListener(this);
I was facing the same problem but after doing this I got the solution
First Paste this code in your main activity (where you are using Bottom navigation bar)
BottomNavigationView bottomNavigationView = (BottomNavigationView) findViewById(R.id.navigation);
BottomNavigationViewHelper.disableShiftMode(bottomNavigationView);
And then create a class named BottomNavigationViewHelper and paste the following code.
public class BottomNavigationViewHelper {
public static void disableShiftMode(BottomNavigationView view) {
BottomNavigationMenuView menuView = (BottomNavigationMenuView) view.getChildAt(0);
try {
Field shiftingMode = menuView.getClass().getDeclaredField("mShiftingMode");
shiftingMode.setAccessible(true);
shiftingMode.setBoolean(menuView, false);
shiftingMode.setAccessible(false);
for (int i = 0; i < menuView.getChildCount(); i++) {
BottomNavigationItemView item = (BottomNavigationItemView) menuView.getChildAt(i);
//noinspection RestrictedApi
item.setShiftingMode(false);
// set once again checked value, so view will be updated
//noinspection RestrictedApi
item.setChecked(item.getItemData().isChecked());
}
} catch (NoSuchFieldException e) {
Log.e("BNVHelper", "Unable to get shift mode field", e);
} catch (IllegalAccessException e) {
Log.e("BNVHelper", "Unable to change value of shift mode", e);
}
}
}
Hope It helps
Try this.
getSupportFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
#Override
public void onBackStackChanged() {
// Gets the previous global stack count
int previousStackCount = mPreviousStackCount;
// Gets a FragmentManager instance
FragmentManager localFragmentManager = getSupportFragmentManager();
// Sets the current back stack count
int currentStackCount = localFragmentManager.getBackStackEntryCount();
// Re-sets the global stack count to be the current count
mPreviousStackCount = currentStackCount;
boolean popping = currentStackCount < previousStackCount;
if(popping){
bottomNavigationView.getMenu().getItem(0).setChecked(true);
}
}
});
Please try this solution.
I have made changes in your code given in question.
I have assumed that on back pressing first time your app will come back to home fragment (in your case Announcement fragment) and if you back press again, the app will close.
This flow will also reflect in bottom navigation bar.
public class MainActivity extends AppCompatActivity {
private static final String BACK_STACK_ROOT_TAG = "root_home_fragment";
private static final String SELECTED_ITEM = "selected_item";
private Fragment fragment;
private FragmentManager fragmentManager;
private BottomNavigationView bottomNavigationView;
private Toolbar toolbar;
private MenuItem menuItemSelected;
private int mMenuItemSelected;
private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
= new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
boolean selected = false;
switch (item.getItemId()) {
case R.id.action_announcement:
fragment = AnnouncementFragment.newInstance();
selected = true;
break;
case R.id.action_menu:
fragment = MenuFragment.newInstance();
selected = true;
break;
case R.id.action_menu_reports:
fragment = ReportFragment.newInstance();
selected = true;
break;
case R.id.action_setting:
fragment = SettingFragment.newInstance();
selected = true;
}
if(fragment !=null){
fragmentManager = getFragmentManager();
switch (item.getItemId()) {
case R.id.action_announcement:
// Pop every fragment from backstack including home fragment.
fragmentManager.popBackStack(BACK_STACK_ROOT_TAG, FragmentManager.POP_BACK_STACK_INCLUSIVE);
fragmentManager.beginTransaction()
.replace(R.id.content, fragment)
.addToBackStack(BACK_STACK_ROOT_TAG)
.commit();
break;
default:
fragmentManager.beginTransaction()
.replace(R.id.content, fragment)
.addToBackStack(null)
.commit();
break;
}
}
return selected;
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
bottomNavigationView = (BottomNavigationView) findViewById(R.id.bottom_navigation);
bottomNavigationView.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
//Always load first fragment as default
bottomNavigationView.setSelectedItemId(R.id.action_announcement);
if (savedInstanceState != null) {
mMenuItemSelected = savedInstanceState.getInt(SELECTED_ITEM, 0);
menuItemSelected = bottomNavigationView.getMenu().findItem(mMenuItemSelected);
} else {
menuItemSelected = bottomNavigationView.getMenu().getItem(0);
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
outState.putInt(SELECTED_ITEM, mMenuItemSelected);
super.onSaveInstanceState(outState);
}
public void onBackPressed() {
int count = getFragmentManager().getBackStackEntryCount();
if(count >1){
// We have lots of fragment on backstack to be popped.
// Pop till the root fragment.
getFragmentManager().popBackStack(BACK_STACK_ROOT_TAG, FragmentManager.POP_BACK_STACK_INCLUSIVE);
bottomNavigationView.setSelectedItemId(R.id.action_announcement);
}
else{
// Close the application when we are on home fragment.
supportFinishAfterTransition();
}
}
}
Most time when you, press back button, old fragment in the back stack,
are recalled. therefore the system call this onCreateView() method
there add this code
val bottomNav = activity?.findViewById<BottomNavigationView>(R.id.activity_main_bottom_navigation)
bottomNav?.selectedItemId = R.id.the_id_of_the_icon__that_represent_the_fragment
I did this after trying all and everything and at last it worked -_- .I have pasted this 2 override method in my each and every activity that i am surfing through my bottom navigation.
#Override
protected void onResume() {
super.onResume();
bottomNavigationView = (BottomNavigationView) findViewById(R.id.bottom_navigation_Menu_name);
bottomNavigationView.getMenu().getItem(Menu_item_position).setChecked(true);
}
#Override
protected void onRestart() {
super.onRestart();
bottomNavigationView = (BottomNavigationView) findViewById(R.id.bottom_navigation_Menu_name);
bottomNavigationView.getMenu().getItem(Menu_item_position).setChecked(true);
}
Late answer but here it goes.
Let's say you have a BottomNavigation inside MainActivity with 4 Fragments.
FragmentA
FragmentB
FragmentC
FragmentD
If your are adding each fragment to backstack like so:
With kotlin:
main_bottom_navigation.setOnNavigationItemSelectedListener { item ->
var fragment: Fragment? = null
when (item.itemId) {
R.id.nav_a -> fragment = FragmentA()
R.id.nav_b -> fragment = FragmentB()
R.id.nav_c -> fragment = FragmentC()
R.id.nav_d -> fragment = FragmentD()
}
supportFragmentManager
.beginTransaction()
.setCustomAnimations(R.anim.abc_fade_in, R.anim.abc_fade_out)
.replace(R.id.home_content, fragment!!)
.addToBackStack(fragment.tag)
.commit()
true
}
You dont really need to override onBackPressed() inside the MainActivity but explicitly cast on each fragment and assigning the BottomNavigation like this:
FragmentA.kt
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
(activity as MainActivity).main_bottom_navigation.menu.getItem(0).isChecked = true
}
FragmentB.kt
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
(activity as MainActivity).main_bottom_navigation.menu.getItem(1).isChecked = true
}
FragmentC.kt
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
(activity as MainActivity).main_bottom_navigation.menu.getItem(2).isChecked = true
}
FragmentD.kt
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
(activity as MainActivity).main_bottom_navigation.menu.getItem(3).isChecked = true
}
Like this the fragment backstack will properly pop and even exit application when it reaches 0.
This is what I did to handle back press in the activity:
#Override
public void onBackPressed() {
super.onBackPressed();
if(homeFragment.isVisible()){
navView.setSelectedItemId(R.id.nav_home);
}
if(searchFragment.isVisible()){
navView.setSelectedItemId(R.id.nav_search);
}
if(myProfileFragment.isVisible()){
navView.setSelectedItemId(R.id.nav_profile);
}
}
this code is work for me:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
OneSignal.startInit(this)
.inFocusDisplaying(OneSignal.OSInFocusDisplayOption.Notification)
.unsubscribeWhenNotificationsAreDisabled(true)
.init();
bottomNavigationView = findViewById(R.id.bottomNav);
frameLayout = findViewById(R.id.main_frame);
homeFragment = new HomeFragment();
aboutUsFragment = new AboutUsFragment();
recipesFragment = new RecipesFragment();
knowledgeFragment = new KnowledgeFragment();
contactFragment = new ContactFragment();
loadFragment(homeFragment);
bottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem menuItem) {
switch (menuItem.getItemId()) {
case R.id.home:
//mManiNav.setItemBackgroundResource(R.color.blue);
loadFragment(homeFragment);
return true;
case R.id.deposit:
// mManiNav.setItemBackgroundResource(R.color.colorAccent);
loadFragment(recipesFragment);
return true;
case R.id.exchange:
//mManiNav.setItemBackgroundResource(R.color.colorPrimary);
loadFragment(knowledgeFragment);
return true;
case R.id.profile:
// mManiNav.setItemBackgroundResource(R.color.light_blue);
loadFragment(aboutUsFragment);
return true;
case R.id.payout:
// mManiNav.setItemBackgroundResource(R.color.light_blue);
loadFragment(contactFragment);
return true;
default:
return false;
}
}
});
}
Here the load fragment class:
private void loadFragment(Fragment fragment) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.main_frame, fragment);
transaction.addToBackStack(null);
transaction.commit();
}
Here is the popBackStackTillEntry method:
enter code here public void popBackStackTillEntry(int entryIndex) {
if (getSupportFragmentManager() == null) {
return;
}
if (getSupportFragmentManager().getBackStackEntryCount() <= entryIndex) {
return;
}
FragmentManager.BackStackEntry entry = getSupportFragmentManager().getBackStackEntryAt(
entryIndex);
if (entry != null) {
getSupportFragmentManager().popBackStackImmediate(entry.getId(),
FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
}
Here is the backpress method:
boolean doubleBackToExitPressedOnce = false;
#Override
public void onBackPressed() {
if (doubleBackToExitPressedOnce) {
popBackStackTillEntry(0);
moveTaskToBack(true);
System.exit(0);
return;
}
this.doubleBackToExitPressedOnce = true;
loadFragment(new HomeFragment());
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
doubleBackToExitPressedOnce=false;
}
}, 2000);
}
This is a simple and complete working code in Kotlin.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
bottomNavigationView = findViewById(R.id.bottom_navigation)
bottomNavigationView.setOnItemSelectedListener {menuItem ->
when(menuItem.itemId){
R.id.navBottom_menu_1 -> nextFragment(Fragment_1())
R.id.navBottom_menu_2 -> nextFragment(Fragment_2())
R.id.navBottom_menu_3 -> nextFragment(Fragment_3())
R.id.navBottom_menu_4 -> nextFragment(Fragment_4())
else ->false
}
}
}
fun nextFragment(fm:Fragment): Boolean {
supportFragmentManager.beginTransaction().replace(R.id.linearLayout_rootFragment, fm).commit()
return true
}
fun isMenuChecked(itemIndex:Int):Boolean{
return bottomNavigationView.menu.getItem(itemIndex).isChecked
}
fun setMenuItemChecked(itemIndex:Int){
bottomNavigationView.menu.getItem(itemIndex).isChecked = true
}
override fun onBackPressed() {
when(true){
isMenuChecked(3) -> {nextFragment(Fragment_3()) ; setMenuItemChecked(2) }
isMenuChecked(2) -> {nextFragment(Fragment_2()) ; setMenuItemChecked(1) }
isMenuChecked(1) -> {nextFragment(Fragment_1()) ; setMenuItemChecked(0) }
else -> super.onBackPressed()
}
}
}
This is how I solved my,
Wrap your main widget in WillPopScope() and set a function in the onWillpop: as this
Future<bool> _onBackpress() {
if (_currentpage != 0) {
setState(() {
_currentpage--;//decreases number of pages till the fisrt page
});
} else {
// a function to close the app
}
}
I am using 3 Fragment(HomeFragment,RegisterFragment and NewsFragment).How to move from NewsFragment to direct HomeFragment, when I click on Back Button. I don,t want to move to other Fragment ,when I click on Back Button.
I made a utility class which will control my fragment navigation.
Here is what this class looks like:
public class FragmentController {
private static final String TAG = FragmentController.class.getCanonicalName();
private static FragmentController mInstance;
private ArrayList<BaseFragment> mFragmentsList;
private BaseActivity mActivity;
private FrameLayout mFragmentContainer;
public FragmentController(BaseActivity activity) {
set(activity);
}
public static FragmentController getInstance(BaseActivity activity) {
if (mInstance == null)
mInstance = new FragmentController(activity);
return mInstance;
}
public static void setInstance(FragmentController mInstance) {
FragmentController.mInstance = mInstance;
}
public void set(BaseActivity activity) {
mActivity = activity;
if (mActivity instanceof MainActivity) {
mFragmentContainer = ((MainActivity) mActivity).getFragmentContainer();
}
mFragmentsList = new ArrayList<>();
}
public void addFirstFragment(BaseFragment fragment) {
mFragmentsList.add(fragment);
}
public void presentFragment(BaseFragment fragment, boolean removeAllFromBackstack) {
try {
Log.d(TAG, "presentFragment: " + fragment.getTagFm());
if (mActivity.getCurrentFocus() != null) {
ViewUtils.hideKeyboard(mActivity.getCurrentFocus());
}
FragmentTransaction ft = mActivity.getSupportFragmentManager().beginTransaction();
ft.setCustomAnimations(R.anim.fade_in, R.anim.fade_out);
ft.replace(mFragmentContainer.getId(), fragment, fragment.getTagFm());
ft.addToBackStack(fragment.getTagFm());
ft.commitAllowingStateLoss();
if (mFragmentsList.size() != 0)
if (removeAllFromBackstack) {
if (mFragmentsList.size() == 2) {
mFragmentsList.remove(1);
} else if (mFragmentsList.size() > 2) {
mFragmentsList.subList(1, mFragmentsList.size()).clear();
}
}
if (!isFragmentPresent(fragment))
mFragmentsList.add(fragment);
} catch (Exception e) {
e.printStackTrace();
}
}
public void removeSecondFragment() {
mFragmentsList.remove(1);
}
private boolean isFragmentPresent(BaseFragment fragment) {
for (BaseFragment baseFragment : mFragmentsList) {
if (baseFragment.getTagFm().equals(fragment.getTagFm()))
return true;
}
return false;
}
public BaseFragment getCurrentFragment() {
return mFragmentsList.get(mFragmentsList.size() - 1);
}
public ArrayList<BaseFragment> getFragmentsList() {
return mFragmentsList;
}
}
Now, I instantiate this class in a Activity
mFragmentController = FragmentController.getInstance(this);
and now, I do this onBackPressed() from my Activity
#Override
public void onBackPressed() {
if (mFragmentController.getFragmentsList().size() == 1) {
finish();
}
else {
mFragmentController.getFragmentsList().remove(mFragmentController.getFragmentsList().size() - 1);
mFragmentController.presentFragment(mFragmentController.getFragmentsList().get(mFragmentController.getFragmentsList().size() - 1), false);
}
}
In FragmentController class, you will see that im using method getTagFm() on BaseFragment class. This is basically for recognizing which fragment is present in que and which is not. BaseFragment class will be something like this:
public class BaseFragment extends Fragment {
public String getTagFm() {
if (this.getClass().getSimpleName().equals(LoginFragment.class.getSimpleName())) {
return Constants.TAG_FRAGMENT_LOGIN;
} else if (this.getClass().getSimpleName().equals(OrderFragment.class.getSimpleName())) {
return Constants.TAG_FRAGMENT_ORDER;
} else if (this.getClass().getSimpleName().equals(ProgramFragment.class.getSimpleName())) {
return Constants.TAG_FRAGMENT_PROGRAM;
}
return Constants.TAG_FRAGMENT_ORDER;
}
}
where all of these fragments(LoginFragment, OrderFragment, ProgramFragment) extend BaseFragment.
Hope this helps somebody.
In NewsFragment :
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (Integer.parseInt(android.os.Build.VERSION.SDK) > 5
&& keyCode == KeyEvent.KEYCODE_BACK
&& event.getRepeatCount() == 0) {
onBackPressed();
return true;
}
return super.onKeyDown(keyCode, event);
}
#Override
public void onBackPressed() {
HomeFragment f = (HomeFragment) getSupportFragmentManager().findFragmentById(R.id.fragment_home);
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.show(f);
}
You may have an Activity handling all this fragments replacements. In this Activity, if you define a variable with the actual showing fragment, you can override onBackPressed and checks if its showing NewsFragment and replace it with HomeFragment.
#Override
public void onBackPressed() {
if(actualFragment instanceof NewsFragment) {
HomeFragment homeFragment = new HomeFragment();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fragment_container, homeFragment);
transaction.commit();
}
}
This works form me when I press the return button!
I don't know your fragment structure, but I use a single layout and replace it with the respective fragment.
Here's my code:
#Override
//Pressed return button - returns to the results menu
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){
frag_name frag_name = new frag_name();
FragmentManager manager = getActivity().getSupportFragmentManager();
manager.beginTransaction().replace(R.id.yourlayout, frag_name, frag_name.getTag()).commit();
return true;
}
return false;
}
});
}
Instead of checking each fragment on back press, maintain one stack which keeps the track of each fragment in view hierarchy.
Stack<Fragment> fragmentStack= new Stack<Fragment>();
// add first fragment
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction ft = fragmentManager.beginTransaction();
ft.add(R.id.container, "your fragment object");
//push it in stack
fragmentStack.push(homeListFragment);
ft.commit();
// add second fragment
ResultListFragment resultListFragment = new ResultListFragment();
ft.add(R.id.container, resultListFragment);
fragmentStack.lastElement().onPause();
ft.hide(fragmentStack.lastElement());
fragmentStack.push(resultListFragment);
ft.commit();
//now back button press logic
#Override
public void onBackPressed() {
if (fragmentStack.size() == 2) {
FragmentTransaction ft = fragmentManager.beginTransaction();
fragmentStack.lastElement().onPause();
ft.remove(fragmentStack.pop());
fragmentStack.lastElement().onResume();
ft.show(fragmentStack.lastElement());
ft.commit();
} else {
super.onBackPressed();
}
}
I have a main activity with navigation drawer and a button to load fragment.
When the main ativity is launched I load the MainFragment.
In this moment all works well. The hamburger icon is showing and my Main fragment was loaded.
Next, I click a button and load a secondFragment. After I load the second fragment, I can use the backbutton and homebutton to come back to main activity without problems.
When I am with second fragment loaded and I make a rotation screen, the back button continues to work well, but the home button disappears and hamburger icon appears.
What am i doing wrong?
public class MainActivity extends AppCompatActivity {
private ActionBarDrawerToggle actionBarDrawerToggle;
private DrawerLayout drawerLayout;
private Toolbar toolbar;
private CharSequence mDrawerTitle;
private CharSequence mTitle;
private String mSubTitle;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
initNavigationDrawer();
if (savedInstanceState != null) {
return;
}
MainActivityFragment mainFragment = new MainActivityFragment();
firstFragment.setArguments(getIntent().getExtras());
// Add the fragment to the 'fragment_container' FrameLayout
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
//transaction.replace(R.id.fragment_container, firstFragment);
transaction.replace(R.id.fragment_container, mainFragment, "princ");
transaction.commit();
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Only handle with DrawerToggle if the drawer indicator is enabled.
if (actionBarDrawerToggle.isDrawerIndicatorEnabled() &&
actionBarDrawerToggle.onOptionsItemSelected(item)) {
return true;
}
// Handle your other action bar items...
return super.onOptionsItemSelected(item);
}
}
public Fragment getCurrentFragment(){
FragmentManager frgmgr = getSupportFragmentManager();
return frgmgr.findFragmentById(R.id.fragment_container);
}
#Override
public void onBackPressed() {
if (drawerLayout != null) {
if (drawerLayout.isDrawerOpen(GravityCompat.START)) {
drawerLayout.closeDrawer(GravityCompat.START);
return;
}
}
if ((getCurrentFragment() instanceof MainFragment)) {
finish();
} else if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
getSupportFragmentManager().popBackStack();
} else super.onBackPressed();
}
public void initNavigationDrawer() {
NavigationView navigationView = (NavigationView) findViewById(R.id.navigation_view);
navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(MenuItem menuItem) {
FragmentManager frgmgr = getSupportFragmentManager();
FragmentTransaction transaction = frgmgr.beginTransaction();
Fragment cur_frag;
// Handle navigation view item clicks here.
int id = menuItem.getItemId();
switch (id) {
case R.id.home:
cur_frag = frgmgr.findFragmentById(R.id.fragment_container);
if (!(cur_frag instanceof MainActivityFragment)) {
MainActivityFragment frag = new MainActivityFragment();
transaction.setCustomAnimations(R.anim.enter_from_left, R.anim.exit_to_right, R.anim.enter_from_right, R.anim.exit_to_left);
transaction.replace(R.id.fragment_container, frag);
transaction.commit();
break;
}
drawerLayout.closeDrawers();
break;
case R.id.logout_drw:
finish();
}
drawerLayout.closeDrawer(GravityCompat.START);
return true;
}
});
View header = navigationView.getHeaderView(0);
TextView tv_email = (TextView) header.findViewById(R.id.tv_email);
tv_email.setText("Agendamento");
drawerLayout = (DrawerLayout) findViewById(R.id.drawer);
mTitle = mDrawerTitle = getTitle();
actionBarDrawerToggle = new ActionBarDrawerToggle(this, drawerLayout, toolbar, R.string.drawer_open, R.string.drawer_close) {
#Override
public void onDrawerClosed(View v) {
super.onDrawerClosed(v);
}
#Override
public void onDrawerOpened(View v) {
super.onDrawerOpened(v);
}
};
drawerLayout.addDrawerListener(actionBarDrawerToggle);
actionBarDrawerToggle.syncState();
if (toolbar != null) {
getSupportFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
#Override
public void onBackStackChanged() {
int i=getSupportFragmentManager().getBackStackEntryCount();
if ((i > 0) || (!(getCurrentFragment() instanceof MainActivityFragment))) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true); // show back button
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
onBackPressed();
}
});
} else {
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
actionBarDrawerToggle.syncState();
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
drawerLayout.openDrawer(GravityCompat.START);
}
});
}
}
});
}
}
}
Main Fragment:
public class MainFragment extends Fragment {
public MainFragment() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view=inflater.inflate(R.layout.fragment_main, container, false);
Button butCons= (Button) view.findViewById(R.id.butcons);
butCons.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
SecundaryFrag frag = new SecundaryFragFrag();
// Add the fragment to the 'fragment_container' FrameLayout
FragmentTransaction transaction=getFragmentManager().beginTransaction();
transaction.setCustomAnimations(R.anim.enter_from_left, R.anim.exit_to_right, R.anim.enter_from_right, R.anim.exit_to_left);
transaction.replace(R.id.fragment_container, frag);
transaction.addToBackStack(null);
transaction.commit();
}
});
return view;
}
}
Secondary Fragment:
public class SecundaryFrag extends Fragment{
public SecundaryFrag() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view=inflater.inflate(R.layout.fragment_consulta_ag, container, false);
return view;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
((MainActivity)getActivity()).onBackPressed();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
}
After Rotation:
Main activty with main fragment:
Before Rotation:
I believe it is related to the fact that the view is recreated after the orientation change. I would take a closer look to the onCreate() from the MainActivity in particular when the
if (savedInstanceState != null) {
return;
}
is triggered.
One option is to retain the fragments and restoring them onCreate. Also you could turn off the recreation by catching the orientation and handle it yourself in the application, you can see here both options explained developer.android.com/guide/topics/resources/
I have a Mainactivity which contains a Layout which is parent of 4 sub layout. on clicking on sub layout i am going to a new fragment replacing main layout. But i cant go back to MainActivity after pressing Back button
MainActivity.java
public class MainActivity extends AppCompatActivity {
RelativeLayout aboutUs;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
aboutUs = (RelativeLayout) findViewById(R.id.aboutUs);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
}
//click methods goes here
public void clickAboutUs(View view){
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
FragmentAboutUs fragmentAboutUs = new FragmentAboutUs();
fragmentTransaction.replace(R.id.fragment_container,fragmentAboutUs);
fragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean 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);
}
}
FragmentAboutUs.java
public class FragmentAboutUs extends Fragment
{
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.about_us, container,false);
return view;
}
}
How to go back to main page again after pressing back button from fragment.
Try Like this
public boolean popFragment() {
boolean isPop = false;
Fragment currentFragment = getSupportFragmentManager()
.findFragmentById(R.id.flContent);
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
isPop = true;
getSupportFragmentManager().popBackStackImmediate();
}
return isPop;
}
#Override
public void onBackPressed() {
if (!popFragment()) {
finish();
}
}
public void replaceFragment(Fragment fragment, boolean addToBackStack) {
FragmentTransaction transaction = getSupportFragmentManager()
.beginTransaction();
if (addToBackStack) {
transaction.addToBackStack(null);
} else {
getSupportFragmentManager().popBackStack(null,
FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
transaction.replace(R.id.fragment_container, fragment);
transaction.commit();
getSupportFragmentManager().executePendingTransactions();
}
add above method is in your parent Activity
And Use like
FragmentAboutUs fragmentAboutUs = new FragmentAboutUs();
replaceFragment(fragmentAboutUs , true);
If you have one Activity and four fragments then set onBackPressed() as below in your MainActivity.
#Override
public void onBackPressed()
{
super.onBackPressed();
finish();
}
And in fragments:
#Override
public void onResume() {
super.onResume();
new PlayListFragment();
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){
if(getFragmentManager().getBackStackEntryCount() > 0) {
getFragmentManager().popBackStack();
}
return true;
}
return false;
}
});
}
You can Override the onBackPressed of MainActivity
#Override
public void onBackPressed() {
if (getFragmentManager().getBackStackEntryCount() > 1) {
getFragmentManager().popBackStack();
} else {
super.onBackPressed();
}
}
Here is how it can be done in Xamarin:
Load fragment (I wrote helper method for that, but it's not necessary):
public void LoadFragment(Activity activity, Fragment fragment)
{
var backStateName = fragment.GetType().Name;
var fm = activity.FragmentManager;
var ft = fm.BeginTransaction();
ft.Replace(Resource.Id.mainContainer, fragment);
ft.AddToBackStack(backStateName);
ft.Commit();
}
Back button (in MainActivity):
public override void OnBackPressed()
{
if (isNavDrawerOpen()) drawerLayout.CloseDrawers();
else
{
var backStackEntryCount = FragmentManager.BackStackEntryCount;
if (backStackEntryCount == 1) Finish();
else if (backStackEntryCount > 1) FragmentManager.PopBackStack();
else base.OnBackPressed();
}
}
isNavDrawerOpen method:
bool isNavDrawerOpen()
{
return drawerLayout != null && drawerLayout.IsDrawerOpen(Android.Support.V4.View.GravityCompat.Start);
}
I am working on a project and I need to be able to use the back button in each fragment to navigate between previous fragments, I have methods written to do so by using a back arrow in the action bar, however, I want to be able to use the same functionality on the back button pressed. I don't want to use the back stack. Is there a way to do this?
EDIT
Rather than using the back stack I want to be able to call the go back to previous method below when the user clicks the back button. I need to used the gobackpressed method within fragments. Is this possible? I hope this is clear and concise. Apologies for any confusion caused above.
Go Back to Previous
public void gobackToPreviousFragment(String preFragmentTag, Fragment preFragment){
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.setCustomAnimations(R.animator.close_slide_in,R.animator.close_slide_out);
ft.show(preFragment);
//**BY REMOVING FRAGMENT, WHEN USER TRIES TO REVISIT, FRAGMENT IS BLACK**
ft.remove(fm.findFragmentByTag(Misc.currentContentFragmentTag));
ft.addToBackStack(null);
ft.commit();
Misc.currentContentFragmentTag = preFragmentTag;
createBar(preFragment);
}
Go Forward
public void gotoNextFragment(String nextTag, Fragment nextFragment){
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.setCustomAnimations(R.animator.enter_slide_in, R.animator.enter_slide_out);
boolean newlyCreated = false;
if(nextFragment == null){
nextFragment = Fragment.instantiate(this, nextTag);
newlyCreated = true;
}
//hide current fragment
ft.hide(fm.findFragmentByTag(Misc.currentContentFragmentTag));
if(newlyCreated){
ft.add(R.id.content_frame, nextFragment, nextTag);
}
else{
ft.show(nextFragment);
}
ft.addToBackStack(null);
ft.commit();
Misc.currentContentFragmentTag = nextTag;
createBar(nextFragment);
}
These are how I navigate back and forth, and I'd like to be able to implement the go back method on the onBackPressed(). Does this make sense?
I didn't find any good answer about this problem, so this is my solution.
If you want to get backPress in each fragment do the following.
create interface OnBackPressedListener
public interface OnBackPressedListener {
void onBackPressed();
}
That each fragment that wants to be informed of backPress implements this interface.
In parent activity , you can override onBackPressed()
#Override
public void onBackPressed() {
List<Fragment> fragmentList = getSupportFragmentManager().getFragments();
if (fragmentList != null) {
//TODO: Perform your logic to pass back press here
for(Fragment fragment : fragmentList){
if(fragment instanceof OnBackPressedListener){
((OnBackPressedListener)fragment).onBackPressed();
}
}
}
}
Why don't you want to use the back stack? If there is an underlying problem or confusion maybe we can clear it up for you.
If you want to stick with your requirement just override your Activity's onBackPressed() method and call whatever method you're calling when the back arrow in your ActionBar gets clicked.
EDIT: How to solve the "black screen" fragment back stack problem:
You can get around that issue by adding a backstack listener to the fragment manager. That listener checks if the fragment back stack is empty and finishes the Activity accordingly:
You can set that listener in your Activity's onCreate method:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FragmentManager fm = getFragmentManager();
fm.addOnBackStackChangedListener(new OnBackStackChangedListener() {
#Override
public void onBackStackChanged() {
if(getFragmentManager().getBackStackEntryCount() == 0) finish();
}
});
}
requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
Log.w("a","")
}
})
In the fragment where you would like to handle your back button you should attach stuff to your view in the oncreateview
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.second_fragment, container, false);
v.setOnKeyListener(pressed);
return v;
}
#Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
// TODO Auto-generated method stub
if( keyCode == KeyEvent.KEYCODE_BACK ){
// back to previous fragment by tag
myfragmentclass fragment = (myfragmentclass) getActivity().getSupportFragmentManager().findFragmentByTag(TAG);
if(fragment != null){
(getActivity().getSupportFragmentManager().beginTransaction()).replace(R.id.cf_g1_mainframe_fm, fragment).commit();
}
return true;
}
return false;
}
};
This works for me :D
#Override
public void onResume() {
super.onResume();
if(getView() == null){
return;
}
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's click listener
return true;
}
return false;
}
});}
You can try to override onCreateAnimation, parameter and catch enter==false. This will fire before every back press.
#Override
public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) {
if(!enter){
//leaving fragment
Log.d(TAG,"leaving fragment");
}
return super.onCreateAnimation(transit, enter, nextAnim);
}
For a Fragment you can simply add
getActivity().onBackPressed();
to your code
I found a new way to do it without interfaces. You only need to add the below code to the Fragment’s onCreate() method:
//overriding the fragment's oncreate
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//calling onBackPressedDispatcher and adding call back
requireActivity().onBackPressedDispatcher.addCallback(this) {
//do stuff here
}
}
Use this:
#Override
public void onBackPressed() {
int fragments = getFragmentManager().getBackStackEntryCount();
if (fragments == 1) {
finish();
}
super.onBackPressed();
}