Je travaille sur une barre de navigation inférieure, mais la barre de navigation inférieure ne me convient pas parfaitement.
Ma classe MainActivity
:
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);
}
Et mon dos pressé aussi ne fonctionne pas correctement:
@Override
public void onBackPressed() {
MenuItem homeItem = bottomNavigationView.getMenu().getItem(0);
if (mMenuItemSelected != homeItem.getItemId()) {
selectFragment(homeItem);
} else {
super.onBackPressed();
}
}
Comment devrais-je faire cela parce que le menu du bas a une distribution inégale sur le bar. Comment bien entretenir l'espace du menu sans distribution inégale.
Selon les directives pour Conception du matériel
Sur Android, le bouton Précédent ne permet pas de naviguer entre le bas vues de la barre de navigation.
EDIT: le lien Material Design ne mentionne plus le comportement du bouton Précédent.
En appuyant sur le bouton Précédent, vous pouvez quitter l'application, qui est le comportement par défaut, comme dans Google Photo ...
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.content, fragment);
// note: there is NOT a addToBackStack call
fragmentTransaction.commit();
... ou conduisez l'utilisateur à la section home puis, si on le pousse à nouveau, à la sortie.
Personnellement je trouve ce dernier modèle beaucoup mieux.
Pour l'obtenir sans remplacer onBackPressed
, vous devez identifier le fragment home et le différencier de all les autres
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;
}
});
Ce que vous devez faire maintenant, c'est écrire la méthode viewfragment
qui doit:
commit
Si le fragment est not "type maison", enregistrez-le sur la pile avant La commit
Ajoutez une OnBackStackChangedListener
qui, lorsque la pile diminue, (C’est-à-dire lorsque j’appuie de nouveau), supprime tous les fragments qui sont pas "type de maison" ( POP_BACK_STACK_INCLUSIVE ), nous amenant au fragment de maison
Ci-dessous la méthode complète avec commentaires
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);
}
}
});
}
Essaye ça
@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);
}
}
onBackPressed n'a pas fonctionné pour moi. Donc cela j'ai utilisé.
@Override
protected void onResume() {
super.onResume();
bottomNavigationView.getMenu().getItem(0).setChecked(true);
}
C'est peut-être un peu tard, mais je pense que la meilleure façon de le faire est aussi simple que cela.
@Override
public void onBackPressed() {
if (mBottomNavigationView.getSelectedItemId() == R.id.action_home) {
super.onBackPressed();
} else {
mBottomNavigationView.setSelectedItemId(R.id.action_home);
}
}
J'espère que ça aide et bon codage :)
La meilleure façon de procéder est la suivante: lorsque vous êtes dans le bouton d'accueil, l'application est fermée et lorsqu'un autre bouton est dans le bouton d'accueil.
Ci-dessous je mets mon code:
d'abord, je charge le bouton d'accueil dans la navigation
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();
}
et rappelez-vous ne pas appeler addToBackStack()
. et ensuite gérer la situation par onBackPressed()
:
@Override
public void onBackPressed() {
if (navigation.getSelectedItemId() == R.id.bottomAkhbar) {
super.onBackPressed();
} else {
navigation.setSelectedItemId(R.id.bottomAkhbar);
}
}
Je faisais face au même problème mais après cela, j’ai eu la solution
D'abord, collez ce code dans votre activité principale (où vous utilisez la barre de navigation inférieure)
BottomNavigationView bottomNavigationView = (BottomNavigationView) findViewById(R.id.navigation);
BottomNavigationViewHelper.disableShiftMode(bottomNavigationView);
Et puis créez une classe nommée BottomNavigationViewHelper et collez le code suivant.
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);
}
}
}
J'espère que ça aide
J'ai fait cela après avoir tout essayé et finalement, cela a fonctionné -_-. J'ai collé cette méthode de substitution 2 dans chacune des activités que je surfe dans la navigation inférieure.
@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);
}
Réponse tardive mais ça y est.
Supposons que vous avez un BottomNavigation inside MainActivity avec 4 Fragments .
Si vous ajoutez chaque fragment au backstack, procédez comme suit:
Avec 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
}
Vous n'avez pas vraiment besoin de remplacer onBackPressed () à l'intérieur de MainActivity mais explicitement lancé sur chaque fragment et assigné le BottomNavigation comme ceci:
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
}
De cette manière, le fragment de pile restituera et même quittera l'application lorsqu'il atteindra 0.
Pour ce qui est de votre besoin, vous utiliseriez des fragments de navigation, vous pouvez utiliser Tablayout avec un pageur de vue et effectuer une navigation de fond.
<Android.support.design.widget.TabLayout
Android:id="@+id/tab_layout"
Android:layout_width="match_parent"
Android:layout_height="60dp"></Android.support.design.widget.TabLayout>
puis configurez viewpager avec la disposition des onglets et ajoutez une icône à tablayout dans votre activité
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);
maintenant, gérez tout sur le clic de tablayout et cela fonctionnera bien. tabLayout.addOnTabSelectedListener (this);
Utilisez addToBackStack Method pour appeler un fragment comme celui-ci,
getSupportFragmentManager().beginTransaction().addToBackStack(null).add(R.id.content_home_nav,newFragment).commit();
Utilisez ce code dans votre méthode onBackPressed
if (getSupportFragmentManager().getBackStackEntryCount() > 0 ){
getFragmentManager().popBackStack();
} else {
super.onBackPressed();
}
S'il vous plaît essayer cette solution . J'ai apporté des modifications dans votre code donné en question.
J'ai supposé que lorsque vous appuierez pour la première fois, votre application reviendra au fragment d'origine (dans votre fragment d'annonce) et si vous appuyez à nouveau, l'application se fermera.
Ce flux sera également reflété dans la barre de navigation inférieure.
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();
}
}
}
J'avais le même problème et j'ai donc résolu le problème en utilisant cette méthode: Dans mon activité principale, j'ai une barre de navigation inférieure et un tiroir de navigation, je dois synchroniser les éléments de mon tiroir et de la navigation inférieure:
J'ai créé une méthode pour mon fragment principal et les autres: Mon fragment de remplacement principal:
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();
}
});
}
et ceci est pour mon autre fragment de remplacement:
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();
}
});
}
donc, après cela, je dois synchroniser les éléments dans le tiroir et dans la barre: :
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);
}
}
Alors j'appelle mes fragments comme ça:
MainFragmentChanger(new MainPageFragment(),"Home");
bottomNavigationBar.selectTab(0,false);
changeBottomFragment(new FlashCardFragment(),"flash");
bottomNavigationBar.selectTab(2,false);
changeBottomFragment(new TranslateFragment(),"dic");
bottomNavigationBar.selectTab(3,false);
A la fin, j'appelle changeNavAndBarStatus dans la méthode onResume de mon fragment:
((MainPageActivity)getContext()).changeNavAndBarStats("flash");
C'est tout! tu es prêt!
La plupart du temps, lorsque vous appuyez sur le bouton Précédent, l'ancien fragment de la pile arrière, donc l'appel système cette méthode onCreateView ()
il ajoute ce 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
Essaye ça.
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);
}
}
});