When I change fragment my FAB (FloatingActionButton) not change her image. I've got this method to change image:
private void fabImages(){
final NavHostFragment nhf = (NavHostFragment)getSupportFragmentManager().findFragmentById(R.id.nav_host_fragment_content_main);
if(nhf != null){
Fragment fragmentActual = nhf.getChildFragmentManager().getFragments().get(0);
if(fragmentActual instanceof HomeFragment){
binding.appBarMain.fab.setImageResource(R.drawable.ic_add_auto_blanco);
}else if(fragmentActual instanceof GalleryFragment){
binding.appBarMain.fab.setImageResource(R.drawable.ic_save);
}
}
}
i'm using this activity to my app:
I apply this method in onCreate and onResume from my MainActivity but the image not change, why?
UPDATE:
MainActivity:
public class MainActivity extends AppCompatActivity{
private AppBarConfiguration mAppBarConfiguration;
private ActivityMainBinding binding;
private String horaString, fechaString;
private NombreTallerPreferencia nombreTallerPreferencia;
private PermissionHelper permissionHelper;
private static final int PICK_IMAGE = 1;
public static final String TAG = "logcat";
public static final String BARRA = "/";
private View view_imagen_perfil;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
setSupportActionBar(binding.appBarMain.toolbar);
fabImages(); //method to change image
DrawerLayout drawer = binding.drawerLayout;
NavigationView navigationView = binding.navView;
mAppBarConfiguration = new AppBarConfiguration.Builder(
R.id.nav_home, R.id.nav_gallery, R.id.nav_slideshow)
.setDrawerLayout(drawer)
.build();
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_content_main);
NavigationUI.setupActionBarWithNavController(this, navController, mAppBarConfiguration);
NavigationUI.setupWithNavController(navigationView, navController);
}
#Override
protected void onResume() {
super.onResume();
fabImages(); //method to change image
}
The problem is not in how to set a drawable to the FAB, because you already do that right. But the problem in the place where you do that which is in onResume().
Here is the scenario:
The app is launched, onResume() get triggered, and the fabImages() get called, so, it's HomeFragment, so set R.drawable.ic_add_auto_blanco, and this works with you.
You go to GalleryFragment, so HomeFragment is hidden now and the GalleryFragment is shown, but here the onResume() of the activity won't get called, because the activity is not paused() i.e. onPause() doesn't get called;
While you're at GalleryFragment, If you change the configuration by rotating the device, then onResume() will get called, and so as fabImages(), and fab changes its drawable to R.drawable.ic_save.
So, you need to call fabImages() somewhere else other than the onResume of the activity.
To fix this you need to register a listener in the activity that tracks whenever the navigation changes its current destination, and that through the OnDestinationChangedListener interface:
So, in your activity's onCreate()
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
setSupportActionBar(binding.appBarMain.toolbar);
fabImages(); //method to change image
DrawerLayout drawer = binding.drawerLayout;
NavigationView navigationView = binding.navView;
mAppBarConfiguration = new AppBarConfiguration.Builder(
R.id.nav_home, R.id.nav_gallery, R.id.nav_slideshow)
.setDrawerLayout(drawer)
.build();
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_content_main);
NavigationUI.setupActionBarWithNavController(this, navController, mAppBarConfiguration);
NavigationUI.setupWithNavController(navigationView, navController);
/////////////////////////
// Here is the new code:
/////////////////////////
NavController.OnDestinationChangedListener destinationChangedListener = new NavController.OnDestinationChangedListener() {
#Override
public void onDestinationChanged(#NonNull NavController controller, #NonNull NavDestination destination, #Nullable Bundle arguments) {
if (destination.getId() == R.id.nav_home) {
binding.appBarMain.fab.setImageResource(R.drawable.ic_add_auto_blanco);
} else if (destination.getId() == R.id.nav_gallery) {
binding.appBarMain.fab.setImageResource(R.drawable.ic_save);
}
}
};
navController.addOnDestinationChangedListener(destinationChangedListener);
}
It seems that your application does not have fallback conditional like else just incase your values are null.
You can read more about changing the icon on FAB here on
https://stackoverflow.com/a/32082108/12028348 or from the official android studio documentation
https://developer.android.com/reference/android/support/design/widget/FloatingActionButton.html
Related
HomeActivity
public class HomeActivity extends AppCompatActivity {
private AppBarConfiguration mAppBarConfiguration;
public static Toolbar toolbar;
public static BottomNavigationView bottomNavigationView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
DrawerLayout drawer = findViewById(R.id.drawer_layout);
NavigationView navigationView = findViewById(R.id.nav_view);
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
mAppBarConfiguration = new AppBarConfiguration.Builder(
R.id.nav_home, R.id.nav_gallery, R.id.nav_slideshow,R.id.cartFragment,R.id.wishFragment,R.id.dashboardFragment)
.setDrawerLayout(drawer)
.build();
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
NavigationUI.setupActionBarWithNavController(this, navController, mAppBarConfiguration);
NavigationUI.setupWithNavController(navigationView, navController);
bottomNavigationView = findViewById(R.id.bottomNavigationView);
NavigationUI.setupWithNavController(bottomNavigationView, navController);
}
#Override
public boolean onSupportNavigateUp() {
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
return NavigationUI.navigateUp(navController, mAppBarConfiguration)
|| super.onSupportNavigateUp();
}
}
Cart Fragment in bottom navigation
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_cart, container, false);
HomeActivity main = (HomeActivity) getActivity();
//You can access all public variable and methods of MainActivity.
//simply call
main.setSupportActionBar(toolbar);
main.getSupportActionBar().setDisplayHomeAsUpEnabled(false);
toolbar.setNavigationIcon(R.drawable.back_arrow);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
getActivity().onBackPressed();
bottomNavigationView.setVisibility(View.VISIBLE);
}
});
bottomNavigationView.setVisibility(View.INVISIBLE);
return view;
}
}
In Cat fragment first botttom navigation invisible
when backpress from the cart fragment at that time use bottom navigation visible. because of, without visible bottom navigation backpress in MainActivity bottom navigation didn't show.
***When back from the card fragment and click navigation drawer app crush
public class MainActivity extends AppCompatActivity {
private AppBarConfiguration mAppBarConfiguration;
Fragment fragment = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
DrawerLayout drawer = findViewById(R.id.drawer_layout);
NavigationView navigationView = findViewById(R.id.nav_view);
mAppBarConfiguration = new AppBarConfiguration.Builder(
R.id.nav_home, R.id.nav_gallery,
R.id.nav_tools, R.id.nav_share)
.setDrawerLayout(drawer)
.build();
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
NavigationUI.setupActionBarWithNavController(this, navController, mAppBarConfiguration);
NavigationUI.setupWithNavController(navigationView, navController);
}
#Override
public boolean onSupportNavigateUp() {
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
return NavigationUI.navigateUp(navController, mAppBarConfiguration)
|| super.onSupportNavigateUp();
}
}
I want to implement on click methods to some of my elements in nav view but if I use the following code it doesn't change the title in action bar and it is not consistent can anyone suggest a better way of setting on click listeners for the drawer. I am using the navigation drawer version 2.2.0
navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
if (item.getItemId() == R.id.nav_blog) {
Intent intent = new Intent(MainActivity.this,Blog.class);
startActivity(intent);
}
if (item.getItemId() == R.id.nav_logout){
FirebaseAuth.getInstance().signOut();
Intent i = new Intent(MainActivity.this,StartActivity.class);
startActivity(i);
finish();
}
if (item.getItemId() == R.id.nav_settings){
Intent i = new Intent(MainActivity.this,Settings.class);
startActivity(i);
}
if (item.getItemId() ==R.id.nav_home){
fragment = new HomeFragment();
}
if (item.getItemId() ==R.id.nav_gallery){
fragment = new GalleryFragment();
}
if (item.getItemId() ==R.id.nav_tools){
fragment = new ToolsFragment();
}
if (item.getItemId() ==R.id.nav_cal){
fragment = new CalenderFragment();
}
FragmentManager fragmentManager =
getSupportFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.nav_host_fragment, fragment)
.commit();
DrawerLayout drawer = findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return false;
}
});
My recommendation would be to use Android Annotations. To do so, simply add the following lines to your build.gradle
repositories {
maven {
url = 'https://oss.sonatype.org/content/repositories/snapshots'
}
}
def AASnapshotVersion = '4.7.0-SNAPSHOT'
dependencies {
annotationProcessor "org.androidannotations:androidannotations:$AASnapshotVersion"
implementation "org.androidannotations:androidannotations-api:$AASnapshotVersion"
}
You can now annotate a function with #Click(R.id.nav_home) for exemple to specify that it is an onClickListener.
For more information on AA, you can check their website http://androidannotations.org/ which will direct you to their git page
It can build and run successfully but in virtual device has stopped.
this is the code of my main layout in fragment:
public class BlankFragment14 extends Fragment {
#Override
public View onCreateView( LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState ) {
return inflater.inflate(R.layout.fragment_blank_fragment14, container, false);
}
#Override
public void onCreate( #Nullable Bundle savedInstanceState ) {
super.onCreate(savedInstanceState);
BottomNavigationView bottomNav = getView( ).findViewById(R.id.bottom_navigation);
BottomNavigationView.OnNavigationItemSelectedListener navListener = null;
bottomNav.setOnNavigationItemSelectedListener(navListener);
getFragmentManager( ).beginTransaction( ).replace(R.id.fragment_container1, new ProfileFragment( )).commit( );
navListener = new BottomNavigationView.OnNavigationItemSelectedListener( ) {
#Override
public boolean onNavigationItemSelected( #NonNull MenuItem menuItem ) {
Fragment selectedFragment = null;
switch (menuItem.getItemId( )) {
case R.id.nav_profile1:
selectedFragment = new ProfileFragment( );
break;
case R.id.nav_appointment1:
selectedFragment = new AppointmentFragment( );
break;
case R.id.nav_patientdata1:
selectedFragment = new PatientdataFragment( );
break;
}
getFragmentManager( ).beginTransaction( ).replace(R.id.fragment_container1, selectedFragment).commit( );
return true;
}
};
}
}
I don't know that It can be possible to work ? or I must use activity to be a main layout.
Use Navigation component to implement BottomNavigationView. Your MainActivity must have NavHostFragment, that can display other fragment destinations. In MainActivity's onCreate
setup NavController as shown below:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar myToolbar = (Toolbar) findViewById(R.id.toolbar1);
setSupportActionBar(myToolbar);
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_home, R.id.navigation_dashboard, R.id.navigation_notifications)
.build();
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
//NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
NavigationUI.setupWithNavController(navView, navController);
}
I'm using the default nav bar project edited, so the navbar is oon home.xml and I edited the Main javascript file:
package com.invy55.quadernoelettronico;
import ...
public class MainActivity extends AppCompatActivity {
private AppBarConfiguration mAppBarConfiguration;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SharedPreferences prefs = getSharedPreferences("UserData", MODE_PRIVATE);
String uname = prefs.getString("username","");
String pwd = prefs.getString("password","");
EditText username = findViewById(R.id.username);
username.setText(uname);
EditText password = findViewById(R.id.password);
password.setText(pwd);
}
#Override
public boolean onSupportNavigateUp() {
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
return NavigationUI.navigateUp(navController, mAppBarConfiguration)
|| super.onSupportNavigateUp();
}
public void blogin(View v) {
EditText unameet = findViewById(R.id.username);
String username = unameet.getText().toString();
EditText passw = findViewById(R.id.password);
String password = passw.getText().toString();
SharedPreferences prefs = getSharedPreferences("UserData", MODE_PRIVATE);
SharedPreferences.Editor editor = prefs.edit();
editor.putString("username", username);
editor.putString("password", password);
editor.apply();
setContentView(R.layout.home);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
DrawerLayout drawer = findViewById(R.id.drawer_layout);
NavigationView navigationView = findViewById(R.id.nav_view);
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
mAppBarConfiguration = new AppBarConfiguration.Builder(
R.id.nav_home, R.id.nav_gallery, R.id.nav_slideshow,
R.id.nav_tools, R.id.nav_share, R.id.nav_send)
.setDrawerLayout(drawer)
.build();
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
NavigationUI.setupActionBarWithNavController(this, navController, mAppBarConfiguration);
NavigationUI.setupWithNavController(navigationView, navController);
}
}
All works fine, but when I start the app and get to the home.xml page trought the login button (as you can see in the code up here), the bar displays buggy:
But if then in the menu I press a button like home (which is the current page), it fixes without any problem.
PS: When I click the button Home in the menu it runs this script:
package com.invy55.quadernoelettronico.ui.home;
import ...
public class HomeFragment extends Fragment {
private HomeViewModel homeViewModel;
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);
}
});
return root;
}
}
EDIT
I've removed android:fitsSystemWindows="true" from home.xml and it worked for me.
fitsSystemWindows is applied depth first — ordering matters: it’s the first View that consumes the insets that makes a difference. Just plug next to your Layout/Toolbar in the xml.
android:fitsSystemWindows="true"
I have used google's sample navigation activity. In that I have modified the navigation bar items. I want to start a new activity when an item is clicked.
I have add onNavigationItemClicked event as well, still when I click on the item nothing happens.
public class MainActivity extends AppCompatActivity{
private AppBarConfiguration mAppBarConfiguration;
private TextView name, email;
private DrawerLayout drawer;
private Context context;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
context = this;
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
drawer = findViewById(R.id.drawer_layout);
NavigationView navigationView = findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem menuItem) {
switch (menuItem.getItemId()){
case R.id.nav_my_printers:
Intent intent = new Intent(context, MyPrintersActivity.class);
startActivity(intent);
break;
case R.id.nav_settings:
Toast.makeText(context, "Not yet Implemented", Toast.LENGTH_SHORT).show();
}
return false;
}
});
View headerView = navigationView.getHeaderView(0);
name = headerView.findViewById(R.id.name);
email = headerView.findViewById(R.id.email);
name.setText(SessionClass.getUserInSession().getName());
email.setText(SessionClass.getUserInSession().getEmail());
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
mAppBarConfiguration = new AppBarConfiguration.Builder(
R.id.nav_home, R.id.nav_my_printers, R.id.nav_settings)
.setDrawerLayout(drawer)
.build();
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
NavigationUI.setupActionBarWithNavController(this, navController, mAppBarConfiguration);
NavigationUI.setupWithNavController(navigationView, navController);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onSupportNavigateUp() {
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
return NavigationUI.navigateUp(navController, mAppBarConfiguration)
|| super.onSupportNavigateUp();
}
}
The line
NavigationUI.setupWithNavController(navigationView, navController);
Calls setNavigationItemSelectedListener internally to connect destinations to menu items. This overrides the OnNavigationItemSelectedListener view you've set.
Navigation supports <activity> destinations, allowing you to use the default setupWithNavController functionality out of the box. You'd add an activity destination to your graph that uses the same id as your menu item:
<activity
android:id="#+id/nav_my_printers"
android:name=".MyPrintersActivity"/>
Then the default setupWithNavController will call startActivity for you.