在选定的底部导航视图项上重新创建片段

amo*_*the 43 android android-fragments android-support-library bottomnavigationview

以下是我选择的底部导航视图项的代码

bottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {  
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
    Fragment fragment = null;
    switch (item.getItemId()) {
        case R.id.action_one:
            // Switch to page one
            fragment = FragmentA.newInstance();
            break;
        case R.id.action_two:
            // Switch to page two
            fragment = FragmentB.newInstance();
            break;
        case R.id.action_three:
            // Switch to page three
            fragment = FragmentC.newInstance();
            break;
    }
    getSupportFragmentManager().beginTransaction().replace(R.id.container,fragment,"TAG").commit();
    return true;
}
});
Run Code Online (Sandbox Code Playgroud)

现在我的问题是每次重新创建片段并且不希望每次我都尝试添加addToBackStack(null)时重新创建片段,但是这种情况在后面按钮按下时会不断地从堆栈中弹出片段,这是我不想要的.

有没有办法在选定的底部导航栏上显示片段而无需重新创建片段

Viv*_*ven 21

使用支持库v26,您可以执行此操作

FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();

Fragment curFrag = mFragmentManager.getPrimaryNavigationFragment();
if (curFrag != null) {
    fragmentTransaction.detach(curFrag);
}

Fragment fragment = mFragmentManager.findFragmentByTag(tag);
if (fragment == null) {
    fragment = new YourFragment();
    fragmentTransaction.add(container.getId(), fragment, tag);
} else {
    fragmentTransaction.attach(fragment);
}

fragmentTransaction.setPrimaryNavigationFragment(fragment);
fragmentTransaction.setReorderingAllowed(true);
fragmentTransaction.commitNowAllowingStateLoss();
Run Code Online (Sandbox Code Playgroud)

  • 有关完整示例,您可以查看此 git repo https://github.com/okaybroda/FragmentStateManager (2认同)
  • 当您想在来回移动时保持状态/列表位置等时,您会说这是处理三个目的地之间导航的最佳方式吗?使用这种方法有什么注意事项吗?可能的内存泄漏或需要注意的任何事情?我的生命周期还不是 100% 健全 (2认同)

Nik*_*dva 11

当再次单击当前选定的导航按钮时,此解决方案会阻止重新创建片段。但是,每次用户单击不同的导航按钮时,都会创建一个新片段。

只需添加这条线,以避免重新创建FragmentBottomNavigationView

 bottomNavigation.setOnNavigationItemReselectedListener(new BottomNavigationView.OnNavigationItemReselectedListener() {
            @Override
            public void onNavigationItemReselected(@NonNull MenuItem item) {
             // do nothing here   
            }
        });
Run Code Online (Sandbox Code Playgroud)

或者使用 lambda:

bottomNavigation.setOnNavigationItemReselectedListener(item -> { });
Run Code Online (Sandbox Code Playgroud)

  • `setOnNavigationItemReselectedListener` 已弃用,更改为 `setOnItemReselectedListener` (2认同)

Ste*_*mau 9

这对我来说似乎很好。而不是附加和分离,我使用show或hide来保持片段状态。

    public void changeFragment(Fragment fragment, String tagFragmentName) {

        FragmentManager mFragmentManager = getSupportFragmentManager();
        FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();

        Fragment currentFragment = mFragmentManager.getPrimaryNavigationFragment();
        if (currentFragment != null) {
            fragmentTransaction.hide(currentFragment);
        }

        Fragment fragmentTemp = mFragmentManager.findFragmentByTag(tagFragmentName);
        if (fragmentTemp == null) {
            fragmentTemp = fragment;
            fragmentTransaction.add(R.id.frame_layout, fragmentTemp, tagFragmentName);
        } else {
            fragmentTransaction.show(fragmentTemp);
        }

        fragmentTransaction.setPrimaryNavigationFragment(fragmentTemp);
        fragmentTransaction.setReorderingAllowed(true);
        fragmentTransaction.commitNowAllowingStateLoss();
    }
Run Code Online (Sandbox Code Playgroud)

这就是我的使用方式

     private void initViews() {
        BottomNavigationView bottomNavigationView = findViewById(R.id.navigation);
        bottomNavigationView.setOnNavigationItemSelectedListener
                (new BottomNavigationView.OnNavigationItemSelectedListener() {
                    @Override
                    public boolean onNavigationItemSelected(@NonNull MenuItem item) {
                        Fragment selectedFragment = null;
                        switch (item.getItemId()) {
                            case R.id.explore:
                                changeFragment(new ExploreFragment(), ExploreFragment.class
                                        .getSimpleName());
                                toggleViews(true, "");
                                break;
                            case R.id.favorite:
                                changeFragment(new FavoriteFragment(), FavoriteFragment.class
                                        .getSimpleName());
                                toggleViews(false, "Favorites");
                                break;
                            case R.id.venue:
                                changeFragment(new VenueFragment(), VenueFragment.class.getSimpleName());
                                toggleViews(false, "Venues");
                                break;
                            case R.id.profile:
                                changeFragment(new ProfileFragment(), ProfileFragment.class
                                        .getSimpleName());
                                toggleViews(false, "Profile");
                                break;
                        }
                        return true;
                    }
                });

        //Manually displaying the first fragment - one time only
        changeFragment(new ExploreFragment(), ExploreFragment.class
                .getSimpleName());

    }
Run Code Online (Sandbox Code Playgroud)


Max*_*ell 8

使用时要小心replace.即使提供已存在于内存中replace的片段,也会重新启动片段的生命周期.为避免重新启动,事务对象的方法包括add,showhide,可用于显示正确的片段而无需重新启动它.

private fun switchFragment(index: Int) {
    val transaction = supportFragmentManager.beginTransaction()
    val tag = fragments[index].tag

    // if the fragment has not yet been added to the container, add it first
    if (supportFragmentManager.findFragmentByTag(tag) == null) {
        transaction.add(R.id.container, fragments[index], tag)
    }

    transaction.hide(fragments[navigationBar.currentTabPosition])
    transaction.show(fragments[index])
    transaction.commit()
}
Run Code Online (Sandbox Code Playgroud)

  • 你在那里稍微使用了一些令人困惑的措辞,只是为了澄清:替换不会重新启动片段的生命周期,因为它被添加到UI中 - 它结束当前连接的片段然后添加新的片段,我们只能假设它已被删除,如果删除或者它是第一次添加.所以肯定会重新开始,但不是因为替换正在迫使它.基本上替换=删除(oldFrag)然后添加(newFrag). (2认同)

小智 8

我遇到了同样的问题,终于我找到了解决方案,您可以尝试下面的代码。这对我有用。

import android.support.annotation.NonNull;
import android.support.design.widget.BottomNavigationView;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.MenuItem;
import android.widget.FrameLayout;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {
public BottomNavigationView bv;
public home_fragment home;
public account_fragment afrag;
public other_fragment other;
public FrameLayout fr;
android.support.v4.app.Fragment current;
//public FragmentTransaction frt;
    public static int temp=0;
    final Fragment fragment11 = new account_fragment();
    final Fragment fragment22 = new home_fragment();
    final Fragment fragment33 = new other_fragment();
    final FragmentManager fm = getSupportFragmentManager();
    Fragment active = fragment11;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        bv=(BottomNavigationView) findViewById(R.id.navigationView);


        fm.beginTransaction().add(R.id.main_frame, fragment33, "3").hide(fragment33).commit();
        fm.beginTransaction().add(R.id.main_frame, fragment22, "2").hide(fragment22).commit();
        fm.beginTransaction().add(R.id.main_frame,fragment11, "1").commit();
bv.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {

            @Override
            public boolean onNavigationItemSelected(@NonNull MenuItem item) {
                switch (item.getItemId()) {
                    case R.id.account:
                        fm.beginTransaction().hide(active).show(fragment11).commit();
                        active = fragment11;
                        return true;

                    case R.id.home1:
                        fm.beginTransaction().hide(active).show(fragment22).commit();
                        active = fragment22;
                        return true;

                    case R.id.other:
                        fm.beginTransaction().hide(active).show(fragment33).commit();
                        active = fragment33;
                        return true;
                }
                return false;
            }
        });
      bv.setOnNavigationItemReselectedListener(new BottomNavigationView.OnNavigationItemReselectedListener() {
          @Override
          public void onNavigationItemReselected(@NonNull MenuItem item) {
              Toast.makeText(MainActivity.this, "Reselected", Toast.LENGTH_SHORT).show();

          }
      });


    }

}
Run Code Online (Sandbox Code Playgroud)


aka*_*esh 7

setOnNavigationItemReselectedListener 将是一个更好的解决方案


Rap*_*ier 6

尝试这个 :

bottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
                @Override
                public boolean onNavigationItemSelected(@NonNull MenuItem item) {
                    Fragment fragment = null;
                    Fragment currentFragment = getSupportFragmentManager().findFragmentById(R.id.container);
                    switch (item.getItemId()) {
                        case R.id.action_one:
                            // Switch to page one
                            if (!(currentFragment instanceof FragmentA)) {
                                fragment = FragmentA.newInstance();
                            }
                            break;
                        case R.id.action_two:
                            // Switch to page two
                            if (!(currentFragment instanceof FragmentB)) {
                                fragment = FragmentB.newInstance();
                            }
                            break;
                        case R.id.action_three:
                            // Switch to page three
                            if (!(currentFragment instanceof FragmentC)) {
                                fragment = FragmentC.newInstance();
                            }
                            break;
                    }
                    getSupportFragmentManager().beginTransaction().replace(R.id.container, fragment, "TAG").commit();
                    return true;
                }
            });
Run Code Online (Sandbox Code Playgroud)

这将获得您当前的片段,container如果您再次单击该片段,则不会重新添加该片段。

  • 在您的代码中,如果首先加载FragmentA,则单击第二个而不是加载第二个片段,然后,如果用户单击firstFragment,则也会重新创建。 (7认同)