Search code examples
androidfragmentfloating-action-buttonandroid-architecture-componentsandroid-architecture-navigation

How to Change Image in fab


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:

enter image description here

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
    }

Solution

  • 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);
        
    }