How to navigate back to activity from navigation drawer tabs?
Asked Answered
A

2

1

I have a navigation drawer with 3 main tabs https://i.sstatic.net/SIjdx.jpg. In each of these tabs i.e. settings and the rest, I have implemented a top back button that returns to the home activity when clicked. I have also tried to handle the bottom back button but the problem now is that if I click the bottom back button(of the phone gesture navigation) https://i.sstatic.net/RYW16.jpg, it only exits the app instead of returning back to the home Activity as supposed.

I would like to make it return back to the home activity so that I can be able to navigate through the tabs using both the top and bottom back buttons, what can I do to correct this, please?

I have checked for similar questions on this site and have found no solution yet.

Here is my Settings code(i use the same code for the other tabs as well):

public class Settings extends Fragment {

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.settings, container, false);

        requireActivity().getOnBackPressedDispatcher().addCallback(getViewLifecycleOwner(), new OnBackPressedCallback(true) {
            @Override
            public void handleOnBackPressed() {
                requireActivity().finish();
            }
        });

        return view;

    }
}

EDIT:

HomeActivity:

public class HomeActivity extends AppCompatActivity {
    private DrawerLayout drawer;
    // Last update time, click sound, search button, search panel.
    TextView timeField;
    MediaPlayer player;
    ImageView Search;
    ConstraintLayout searchbar;
    EditText textfield;
    // For scheduling background image change(using constraint layout, start counting from dubai, down to statue of liberty.
    ConstraintLayout constraintLayout;
    public static int count = 0;
    int[] drawable = new int[]{R.drawable.dubai, R.drawable.norway, R.drawable.eiffel_tower, R.drawable.hong_kong, R.drawable.statue_of_liberty,
            R.drawable.beijing, R.drawable.chicago, R.drawable.colombia, R.drawable.vienna, R.drawable.tokyo};
    Timer _t;

    private WeatherDataViewModel viewModel;
    private AppBarConfiguration appBarConfiguration;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_home);
        // use home activity layout.

        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        // Allow activity to make use of the toolbar

        drawer = findViewById(R.id.drawer_layout);
        NavigationView navigationView = findViewById(R.id.nav_view);

        // host 3 fragments along with bottom navigation.
        final NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.fragment);
        assert navHostFragment != null;
        final NavController navController = navHostFragment.getNavController();

        // Passing each menu ID as a set of Ids because each
        // menu should be considered as top level destinations.
        // remove up button from all these fragments
        appBarConfiguration = new AppBarConfiguration.Builder(
                R.id.main_id) // remove up button from all these fragments >> Keep up button in R.id.nav_setting, R.id.nav_slideshow
                .setOpenableLayout(drawer)
                .build();

        // Hiding default Drawer fragment that has the BottomNavView
        navigationView.getMenu().findItem(R.id.main_id).setVisible(false);

        viewModel = new ViewModelProvider(this).get(WeatherDataViewModel.class);

        // Trigger action to open & close navigation drawer
        ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, toolbar
                , R.string.navigation_drawer_open, R.string.navigation_drawer_close);
        drawer.addDrawerListener(toggle);
        toggle.syncState();

        timeField = findViewById(R.id.textView9);
        Search = findViewById(R.id.imageView4);
        textfield = findViewById(R.id.textfield);
        searchbar = findViewById(R.id.searchbar);
        //  find the id's of specific variables.

        NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
        NavigationUI.setupWithNavController(navigationView, navController);

        toggle.setToolbarNavigationClickListener(v -> {
            // Enable the functionality of opening the side drawer, when the burger icon is clicked
            toggle.setDrawerIndicatorEnabled(true);
            navController.navigate(R.id.main_id);
        });

        navController.addOnDestinationChangedListener((controller, destination, arguments) -> {

            // Hide/show top search bar
            if (destination.getId() == R.id.main_id) {
                searchbar.setVisibility(View.VISIBLE);
                toggle.setHomeAsUpIndicator(R.drawable.ic_baseline_arrow_back_24);

            } else {
                searchbar.setVisibility(View.GONE);
            }

            // Fragments that you want to show the back button
            if (destination.getId() == R.id.settings_id || destination.getId() == R.id.ads_upgrade_id || destination.getId() == R.id.privacy_policy_id) {
                // Disable the functionality of opening the side drawer, when the burger icon is clicked
                toggle.setDrawerIndicatorEnabled(false);
            }

        });

        // For scheduling background image change
        constraintLayout = findViewById(R.id.layout);
        constraintLayout.setBackgroundResource(R.drawable.dubai);
        _t = new Timer();
        _t.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                // run on ui thread
                runOnUiThread(() -> {
                    if (count < drawable.length) {

                        constraintLayout.setBackgroundResource(drawable[count]);
                        count = (count + 1) % drawable.length;
                    }
                });
            }
        }, 5000, 5000);

        Search.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                // make click sound when search button is clicked.
                player = MediaPlayer.create(HomeActivity.this, R.raw.click);
                player.start();

                getWeatherData(textfield.getText().toString().trim());
                // make use of some fragment's data

                Fragment currentFragment = navHostFragment.getChildFragmentManager().getFragments().get(0);
                if (currentFragment instanceof MainFragment) {
                    ((MainFragment) currentFragment).getWeatherData(textfield.getText().toString().trim());
                }
            }

            private void getWeatherData(String name) {

                ApiInterface apiInterface = ApiClient.getClient().create(ApiInterface.class);

                Call<Example> call = apiInterface.getWeatherData(name);

                call.enqueue(new Callback<Example>() {
                    @Override
                    public void onResponse(@NonNull Call<Example> call, @NonNull Response<Example> response) {

                        try {
                            assert response.body() != null;
                        } catch (Exception e) {
                            Log.e("TAG", "No City found");
                            Toast.makeText(HomeActivity.this, "No City found", Toast.LENGTH_SHORT).show();
                        }
                    }

                    @Override
                    public void onFailure(@NotNull Call<Example> call, @NotNull Throwable t) {
                        t.printStackTrace();
                    }

                });
            }

        });
    }

    @Override
    public void onBackPressed() {
        if (drawer.isDrawerOpen(GravityCompat.START)) {
            drawer.closeDrawer(GravityCompat.START);
        } else {
            super.onBackPressed();
            // Open/close drawer animation
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (viewModel.getMediaPlayer() != null)
            viewModel.getMediaPlayer().pause();
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (viewModel.getMediaPlayer() != null) {
            viewModel.getMediaPlayer().start();
            viewModel.getMediaPlayer().setLooping(true);
        }
    }

    @Override
    public boolean onSupportNavigateUp() {
        final NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.fragment);
        assert navHostFragment != null;
        final NavController navController = navHostFragment.getNavController();

//        return NavigationUI.navigateUp(navController,drawer);

        return NavigationUI.navigateUp(navController, appBarConfiguration)
                || super.onSupportNavigateUp(); // navigateUp  tries to pop the backstack
    }
}
Acidulous answered 19/1, 2022 at 19:40 Comment(2)
Hey Richard, good day.. Just to understand better, do you want both the top & bottom back buttons to behave the same? for instance when you hit the top up button, you want the app to exit right?; and when you hit the bottom back button you want to return to the main activity?Pertinacity
@zain sure, I want both to behave the same. Currently, the top button already returns back to the home activity, I would like the bottom back button to return as well but without stopping my sound as it is doingAcidulous
P
2

In order to return to the activity instead of existing the app when the bottom back button is clicked:

Remove the below callback from all the relevant fragments like the SettingFragment:

requireActivity().getOnBackPressedDispatcher().addCallback(getViewLifecycleOwner(), new OnBackPressedCallback(true) {
    @Override
    public void handleOnBackPressed() {
        requireActivity().finish();
    }
});

Navigation components will handle the back stack already, so no worries about that. A little issue will come up that when you back to the home activity; you'll see the UP button instead of the burger icon; to fix this, you need to add toggle.setDrawerIndicatorEnabled(true) when you back within addOnDestinationChangedListener

So, in HomeActivity:

navController.addOnDestinationChangedListener((controller, destination, arguments) -> {

    // Hide/show top search bar
    if (destination.getId() == R.id.main_id) {
        searchbar.setVisibility(View.VISIBLE);
        toggle.setHomeAsUpIndicator(R.drawable.ic_baseline_arrow_back_24);
        toggle.setDrawerIndicatorEnabled(true); // <<< Add this line of code to enable the burger icon

    } else {
        searchbar.setVisibility(View.GONE);
    }

    // Fragments that you want to show the back button
    if (destination.getId() == R.id.settings_id || destination.getId() == R.id.ads_upgrade_id || destination.getId() == R.id.privacy_policy_id) {
        // Disable the functionality of opening the side drawer, when the burger icon is clicked
        toggle.setDrawerIndicatorEnabled(false);
    }

});

The sound should continue playing as you are not creating a brand new activity.

Pertinacity answered 21/1, 2022 at 4:39 Comment(3)
Good morning Zain, please can you take a look at this https://mcmap.net/q/1634747/-remove-bottom-navigation-view-with-fragments/16020235 I believe it'll be easier for you to handle since you have the srcAcidulous
Good afternoon @RichardWilson welcome back; let me check if i could answer itPertinacity
Okay Zain, I'm waitingAcidulous
M
1

Use the onBackPressed() function to override the action of the back button. Here's some sample code:

override fun onBackPressed() {
    val intent = Intent(requireActivity(),HomeActivity::class.java)
    requireActivity().startActivity(intent)
}

Write the action you want inside the onBackPressed() function.

Macromolecule answered 19/1, 2022 at 20:46 Comment(8)
I tried the following(using Java): Intent intent = new Intent(Settings.this, HomeActivity.class); startActivity(intent); and got the error: Cannot resolve constructor. Hope you're aware that settings is a fragment, not activity.Acidulous
@RichardWilson I edited my answer, can you try again?Macromolecule
This works. The problem now is that it interferes with my sound, Is there any way to stop the interference? Should I post my activity code so that you could see the sound codes? The app is a weather app that plays sounds continuously, whenever it returns back to activity, my sound is not just paused but stops completelyAcidulous
The top button I implemented doesn't stop it, this one shouldn't as well.Acidulous
@RichardWilson I don't understand how it interferes with the sound. It would be better if you share the sound codes. You can open it as a new question if you want.Macromolecule
You may have a sound problem because the activity has changed. Is your other button switching between fragments?Macromolecule
It'll be better I share it here because it started from this suggestion, I see no reason opening a new question when this one hasn't yet been solved. I didn't have a sound problem before now, yes the other button switches straight to homeactivity without stopping the soundAcidulous
I don't fully understand the problem, but it might be helpful to look here. linkMacromolecule

© 2022 - 2024 — McMap. All rights reserved.