android update navController from button - android

I started a new app with the default android bottom navigation menu.
In the basic main fragment I added the buttons for all the fragments (I want to show them in the bottom navigation but also in the main fragment.)
Then I added this in HomeFragment to handle on button press to switch fragments:
public View onCreateView(#NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
homeViewModel = ViewModelProviders.of(this).get(HomeViewModel.class);
View root = inflater.inflate(R.layout.fragment_home, container, false);
final TextView textView = root.findViewById(R.id.text_home);
homeViewModel.getText().observe(this, new Observer<String>() {
#Override
public void onChanged(#Nullable String s) {
textView.setText(s);
}
});
Button btnConnect = (Button) root.findViewById(R.id.btnConnect);
btnConnect.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Fragment fragment = new ConnectFragment();
replaceFragment(fragment);
}
});
Button btnOptions = (Button) root.findViewById(R.id.btnOptions);
btnOptions.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Fragment fragment = new OptionsFragment();
replaceFragment(fragment);
}
});
return root;
}
private void replaceFragment(Fragment someFragment) {
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.nav_host_fragment, someFragment);
transaction.addToBackStack(null);
transaction.commit();
}
Now I am able to switch between the fragments, but the navigation controller isn't being updated, and when I switch from those buttons to another fragment, in the navigation controller at the bottom, the icons are not updated, and t looks like I am still on the home fragment.
this is the code inside MainActivity for the navigation controller:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
BottomNavigationView navView = findViewById(R.id.nav_view);
AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder(
R.id.navigation_home, R.id.navigation_options, R.id.navigation_contact)
.build();
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
NavigationUI.setupWithNavController(navView, navController);
}
So what do I need to do, in order to make the navigation controller update the icons wen I switch fragments from the customized buttons and not from the navigation controller menu?
EDIT:
here is an image to clarify:
on the left is the main activity, on the middle is how it looks like when I switch fragment by pressing on the button "CONNECT" from the main activity, and on the right is how it looks like if I press the "connect" button from the menu.
I want that the menu will be updated, even when I press the "CONNECT" button from the main activity, and not only from the menu.

You can use something like this
yourBottomNavigationView.setSelectedItemId(R.id.navigation_contact);
When you click on your Button

Related

Android Jetpack Navigation component Condtional navigation issue

I was trying to add conditional navigation following this. But I ran into a problem.
So the steps I followed are:
Created navigation drawer in the MainActivity with HomeFragment as a start destination.
Conditionally navigated to FromBlackFragment from BlankFragment.
Want to go to HomeFragment from FromBlackFragment by clicking up/back button.
The problem is with step 3 above. I am going back to HomeFragment by clicking back button whereas I am navigated to BlankFragment on up button click. The code for step 3 is: (inside FromBlackFragment.java file)
requireActivity().getOnBackPressedDispatcher().addCallback(getViewLifecycleOwner(),
new OnBackPressedCallback(true) {
#Override
public void handleOnBackPressed() {
Navigation.findNavController(view).popBackStack(R.id.homeFragment, false);
}
});
The MainActivity.java file:
public class MainActivity extends AppCompatActivity {
private NavController navController;
private DrawerLayout drawerLayout;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.my_toolbar);
drawerLayout = findViewById(R.id.drawer_layout);
NavigationView navigationView = findViewById(R.id.nav_view);
navController = findNavController(this, R.id.nav_host_fragment);
AppBarConfiguration appBarConfiguration =
new AppBarConfiguration.Builder(navController.getGraph())
.setOpenableLayout(drawerLayout).build();
NavigationUI.setupWithNavController(toolbar, navController, appBarConfiguration);
NavigationUI.setupWithNavController(navigationView, navController);
}
#Override
public boolean onOptionsItemSelected(#NonNull MenuItem item) {
return NavigationUI.onNavDestinationSelected(item, navController)
|| super.onOptionsItemSelected(item);
}
}
BlankFragment.java file:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_blank, container, false);
}
#Override
public void onViewCreated(#NonNull final View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
SharedPreferences sp = requireActivity().getSharedPreferences("Testing",0);
if(!sp.getBoolean("b",false)){
SharedPreferences.Editor editor = sp.edit();
editor.putBoolean("b",true);
editor.apply();
Navigation.findNavController(view).navigate(R.id.fromBlackFragment);
}
}
FromBlackFragment.java file:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_from_black, container, false);
}
#Override
public void onViewCreated(#NonNull final View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
requireActivity().getOnBackPressedDispatcher().addCallback(getViewLifecycleOwner(),
new OnBackPressedCallback(true) {
#Override
public void handleOnBackPressed() {
Navigation.findNavController(view).popBackStack(R.id.homeFragment, false);
}
});
}
Note: Shared preferences used in the code is not part of the problem.
Please help. Thanks.
Edit: (More specifically the question is) How to sync upNavigation and back button?
Step1: In MainActivity's onCreate, you need to call setSupportActionBar(toolbar);
Step2: Call setupActionBarWithNavController() from NavigationUI, passing in the proper arguments, this will:
Set up the ActionBar returned by
AppCompatActivity.getSupportActionBar() for use with a NavController.
Step3: By calling setupActionBarWithNavController(), you should now override onSupportNavigateUp(), putting in the call to navigate:
#Override
public boolean onSupportNavigateUp() {
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
return NavigationUI.navigateUp(navController, appBarConfiguration)
|| super.onSupportNavigateUp();
}
If NavigationUI.navigateUp won't get you to home fragment destination, you maybe want call a Navigation method that explicitly get you there.

Navigation between fragments using BottomNavigationView

There's a NavigationView that opens a fragment, in that fragment there's a BottomNavigationView. The bottom navigation view, should switch between two fragments.
Note: When the app starts, it opens the first blank fragment (called Home), so when I click on the second menu item it opens another fragment (that contains the bottom navigation).
I tried to switch from one fragment to the other using FragmentTransaction in this way:
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener = new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
fragmentManager.popBackStack();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
final Fragment fragment;
if (item.getItemId() == R.id.menu_alert) {
fragment = new IPAlertFragment();
} else {
fragment = new IPStatsFragment();
}
fragmentTransaction.replace(R.id.nav_host_fragment, fragment).commit();
return false;
}
};
BottomNavigationView navigation = (BottomNavigationView) getActivity().findViewById(R.id.bottom_navigation);
navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
}
It works fine when I open the fragment from the navigation menu for the first time, but when I click a second time on the navigation menu, the BottomNavigationView.onNavigationItemSelectedListener doesn't fire anymore and I can't switch from a fragment to the other.
So, I've tried to accomplish my goal using NavController, like the following:
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener = new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
final NavController navController = NavHostFragment.findNavController(NavFragment.this);
if (item.getItemId() == R.id.menu_alert) {
navController.navigate(R.id.action_openAlert);
} else {
navController.navigate(R.id.action_openStats);
}
return false;
}
};
BottomNavigationView navigation = (BottomNavigationView) getActivity().findViewById(R.id.bottom_navigation);
navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
}
But when I navigate to the other fragment the left menu bar change the icon to "back arrow", it's a kind of new activity, and I have to use the back button (or the menu back icon) in order to show the previous tab.
I would like to navigate to a destination fragment overriding the current "screen", as like as the side menu does.
Here is the mobile_navigation.xml:
<fragment
android:id="#+id/nav_ip_alert"
android:name="IPAlertFragment"
android:label="#string/menu_ip"
tools:layout="#layout/fragment_i_p_alert">
<action
android:id="#+id/action_openStats"
app:destination="#id/nav_ip_stats"
app:launchSingleTop="false" />
</fragment>
<fragment
android:id="#+id/nav_ip_stats"
android:name="IPStatsFragment"
android:label="#string/menu_ip"
tools:layout="#layout/stats_tabs">
<action
android:id="#+id/action_openAlert"
app:destination="#id/nav_ip_alert"
app:launchSingleTop="false" />
</fragment>
I don't know what's wrong (espacially with the first solution) any idea?
Thanks.
Finally I solved my problem:
It works fine when I open the fragment from the navigation menu for the first time, but when I click a second time on the navigation menu, the BottomNavigationView.onNavigationItemSelectedListener doesn't fire anymore and I can't switch from a fragment to the other.
The problem was caused by the navigation menu, the listener wasn't called because I used in my activity:
NavigationUI.setupWithNavController(navigationView, navController);
That overrides my OnNavigationItemSelectedListener, so I removed that line and I've setted my listener as the following:
final NavigationView navigationView = findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(new
NavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
FragmentManager fm = getSupportFragmentManager();
fm.popBackStackImmediate();
boolean handled = NavigationUI.onNavDestinationSelected(item, navController);
if (handled) {
ViewParent parent = navigationView.getParent();
if (parent instanceof DrawerLayout) {
((DrawerLayout) parent).closeDrawer(navigationView);
}
}
return handled;
}
});
Here's a piece of NavigationUI that override my listener:
public static void setupWithNavController(#NonNull final NavigationView navigationView,
#NonNull final NavController navController) {
navigationView.setNavigationItemSelectedListener(
new NavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
boolean handled = onNavDestinationSelected(item, navController);
//******* CUTTED ***************
return handled;
}
});
}
So, replacing the setupWithNavController, I can navigate through the tabs correctly.

Bottom Navigation Activity with external button

I am using Bottom Navigation Activity from Android Studio
After setting all the needed bottom tabs, I need to add aditional button for one fragment, but outside the tab zone. And that button is only when the second fragment is called.
Something like in image below
I've set new fragment in navigation/mobile_navigation.xml
<fragment
android:id="#+id/navigation_demografski"
android:name="com.home.Fragment1"
android:label="Podaci o osobama"
tools:layout="#layout/fragment_home" />
<fragment
android:id="#+id/navigation_biometrijski"
android:name="com.home.Fragment2"
android:label="Biometrijski podaci - Desna Ruka"
tools:layout="#layout/fragment_dashboard" />
<fragment
android:id="#+id/navigation_biometrijski2"
android:name="com.home.Fragment3"
android:label="Biometrijski podaci - Lijeva Ruka"
tools:layout="#layout/fragment_dashboard2" />
But I don't know how to call the third fragment from the second fragment.
I tried to use fragmet.replace() but it just overlaps one fragment over the other.
Tabbed activity
public class TabbedActivity extends AppCompatActivity
{
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tabbed);
BottomNavigationView navView = findViewById(R.id.nav_view);
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder(
R.id.navigation_demografski, R.id.navigation_biometrijski).build();
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
NavigationUI.setupWithNavController(navView, navController);
}
}
Use FrameLayout as fragment container, then switch fragments inside it. You could do that by setting OnNavigationItemSelectedListener to BottomNavigationView and using
getSupportFragmentManager().beginTransaction().replace(R.id.frameLayout, selectedFragment).commit();
to switch between the fragments. On mentioned button in second fragment add onClickListener and call previous transaction from Activity with desired fragment as selectedFragment
you can implement by following my code below:
public class MainActivity extends AppCompatActivity implements BottomNavigationView.OnNavigationItemSelectedListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//loading the default fragment
loadFragment(new HomeFragment());
//getting bottom navigation view and attaching the listener
BottomNavigationView navigation = findViewById(R.id.navigation);
navigation.setOnNavigationItemSelectedListener(this);
}
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
Fragment fragment = null;
switch (item.getItemId()) {
case R.id.navigation_home:
fragment = new HomeFragment();
break;
case R.id.navigation_dashboard:
fragment = new DashboardFragment();
break;
case R.id.navigation_notifications:
fragment = new NotificationsFragment();
break;
case R.id.navigation_profile:
fragment = new ProfileFragment();
break;
}
return loadFragment(fragment);
}
private boolean loadFragment(Fragment fragment) {
//switching fragment
if (fragment != null) {
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.fragment_container, fragment)
.commit();
return true;
}
return false;
}
}

Navigation component shared element transitions works for enter but not for popping back

I'm trying to use a shared element animation between 2 fragments, BlankFragment and BlankFragment2. BlankFragment has a recycler view and BlankFragment2 is a details screen. They share an image and I'm using the new navigation component.
In BlankFragment I'm building FragmentNavigator.Extras and passing the extras to my call to navigate with the transition name of the shared image (as its a recycler view and these need to be unique),
In BlankFragment2 I'm receiving this name setting it to my image and setting the setSharedElementEnterTransition
The result is that the enter animation works fine but the exit/return doesn't, I've tried setting them and not setting them (because I believe the navigation component should handle this for me) can anyone help?
MainActivity Navigation Setup
private void setNavigation() {
navController = Navigation.findNavController(this, R.id.main_fragment);
NavigationUI.setupActionBarWithNavController(this, navController);
}
Handling back button
#Override
public boolean onSupportNavigateUp() {
return Navigation.findNavController(this, R.id.main_fragment).navigateUp()
|| super.onSupportNavigateUp();
}
BlankFragment OnClick
#Override
public void onClick(View view, int position) {
NavController navController = Navigation.findNavController(recyclerView);
FragmentNavigator.Extras extras = new FragmentNavigator.Extras.Builder().addSharedElement(view, view.getTransitionName()).build();
BlankFragmentDirections.ActionBlankFragmentToBlankFragment2 directions = BlankFragmentDirections.actionBlankFragmentToBlankFragment2(view.getTransitionName());
navController.navigate(directions,extras);
}
BlankFragment2 onCreate with return/exit transition
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setSharedElementReturnTransition(TransitionInflater.from(getActivity()).inflateTransition(android.R.transition.move));
setExitTransition(TransitionInflater.from(getActivity()).inflateTransition(android.R.transition.no_transition));
setSharedElementEnterTransition(TransitionInflater.from(getActivity()).inflateTransition(android.R.transition.move));
getFragmentArguments();
}
Get Arguments Method
private void getFragmentArguments(){
if (getArguments() != null){
transitionName = BlankFragment2Args.fromBundle(getArguments()).getTransitionName();
Log.d(TAG, "transition name " + transitionName);
}
}
Set image transition name
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
image = view.findViewById(R.id.image);
image.setTransitionName(transitionName);
text = view.findViewById(R.id.text);
}
Java
To Fix on return transition, use viewTreeObserver.addOnPreDrawListener
In BlankFragment (fragment with recycle view)
We need to call postponeEnterTransition(); so the transition
will be pospone
Setup addOnPreDrawListener on recycleView as following
RecyclerView recyclerView = view.findViewById(R.id.recycler_view);
//setup for recycle view adapter
ViewTreeObserver viewTreeObserver = recyclerView.getViewTreeObserver();
viewTreeObserver.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
#Override
public boolean onPreDraw() {
startPostponedEnterTransition();
return true;
}
});
That's it.
Follow this link to get more info on ViewTreeObserver follow this link
FIN !!

Want to move from navigation drawer activity to another screen using fragments to show drawer across all screens

I'm trying for last two days to add fragment next to my drawer activity to get navigation drawer visible across the whole application. I have tried several ways from stackoverflow and many others but still no success. and after that i have to move to 2nd fragment from 1st fragment and so on till the need for navigation drawer.
I want to replace entire view except drawer when i move from from my activity to any fragment. Each fragment have its own layout.xml like an activity(Linear/Relative layouts as parent in them).
Drawer avtivity:
public class MainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener {
#Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
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();
}
});
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.addDrawerListener(toggle);
toggle.syncState();
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
Button btnfragOne = (Button) findViewById(R.id.btnfrag_one);
btnfragOne.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
FragOne fragment = new FragOne();
getSupportFragmentManager().beginTransaction()
.replace(R.id.frag2, fragment, fragment.getClass().getSimpleName()).addToBackStack(null).commit();
}
});
}
1st Fragment class:
public class FragOne extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.frag_one, container, false);
}
// 2nd Fragment class:
public class FragTwo extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.frag_two, container, false);
}
Simply for this task you have to override onNavigationItemSelected method in your Activity, which return id of selected fragment on NavigationDrawer.
Try this,
#Override
public boolean onNavigationItemSelected(MenuItem item) {
//calling the method displayselectedscreen and passing the id of selected menu
displaySelectedFragment(item.getItemId());
return true;
}
Now displaySelectedFragment,
private void displaySelectedScreen(int itemId) {
//creating fragment object
Fragment fragment = null;
//initializing the fragment object which is selected
switch (itemId) {
case R.id.your_fragment_one_id:
fragment = new FragOne();
break;
case R.id.your_fragment_two_id:
fragment = new FragTwo();
break;
}
//replacing the fragment
if (fragment != null) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.main_layout_id_which_is_to_be_replace, fragment);
ft.commit();
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.your_drawer_layout_id);
drawer.closeDrawer(GravityCompat.START);
}
Edit -- If you want navigate from FragOne to FragTwo. Try this,
Create a method in your Activity,
public void showFragTwo(){
FragmentManager manager = getSupportFragmentManager();
FragTwo frag = new FragTwo();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(R.id.your_layout_id_which_is_to_be_replace, frag);
transaction.commit();
}
Then in your FragOne when you want to start FragTwo, call startFragTwo method from Activity as,
((YourActivity) getActivity()).showFragTwo();

Categories

Resources