在我的布局底部,我有一个带有三个片段的 BottomNavigationView 。如果我单击后退按钮,片段正在切换但不是底部图标。我该如何解决?
addToBackStack()有效。也许你有一些建议漂亮的代码。
在活动或片段中使用片段标签是一种好习惯吗?
public class MainActivity extends AppCompatActivity {
private FragmentManager mFragmentManager;
private BottomNavigationView mBottomNavigationView;
private static final String HOME_FRAGMENT = "homeFragment";
private static final String SEARCH_FRAGMENT = "searchFragment";
private static final String SHARE_FRAGMENT = "shareFragment";
private boolean isFirstFragment;
private long mBackPressedTime;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
setBottomNavigationView();
}
private void init() {
mBottomNavigationView = findViewById(R.id.bottomNavigationView);
mFragmentManager = getSupportFragmentManager();
mBackPressedTime = 0;
}
private void setBottomNavigationView() {
setFragment(HomeFragment.newInstance(), HOME_FRAGMENT);
isFirstFragment = true;
mBottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.ic_home:
setFragment(HomeFragment.newInstance(), HOME_FRAGMENT);
return true;
case R.id.ic_search:
setFragment(SearchFragment.newInstance(), SEARCH_FRAGMENT);
return true;
case R.id.ic_circle:
setFragment(ShareFragment.newInstance(), SHARE_FRAGMENT);
return true;
default:
return false;
}
}
});
}
private void setFragment(Fragment fragment, String tag) {
FragmentTransaction transaction = mFragmentManager.beginTransaction();
transaction.replace(R.id.container, fragment, tag);
if (isFirstFragment) {
transaction.addToBackStack(tag);
}
transaction.commit();
}
@Override
public void onBackPressed() {
final long currentTimeMillis = System.currentTimeMillis();
if (mFragmentManager.getBackStackEntryCount() > 0) {
mFragmentManager.popBackStack();
} else if (currentTimeMillis - mBackPressedTime > 2000) {
mBackPressedTime = currentTimeMillis;
Toast.makeText(this, getString(R.string.reach_homescreen), Toast.LENGTH_SHORT).show();
} else {
super.onBackPressed();
}
}
}
答案 0 :(得分:4)
@Hans Baum而不是将您的第一个片段添加到后台堆栈尝试此代码,
@Override
public void onBackPressed() {
if(mBottomNavigationView.getSelectedItemId () != R.id.ic_home)
{
mBottomNavigationView.setSelectedItemId(R.id.ic_home);
}
else
{
super.onBackPressed();
}
}
如果您在Home Fragment中,此代码将退出您的活动,否则如果您在任何其他片段中它将转到Home Fragment。 所以不需要addToBackStack()。所以你的serFragment()方法应该是,
private void setFragment(Fragment fragment, String tag) {
FragmentTransaction transaction = mFragmentManager.beginTransaction();
transaction.replace(R.id.container, fragment, tag);
transaction.commit();
}
希望它有所帮助。
请注意,在您的代码中,您从未将isFirstFragment指定为false,因此我假设所有片段都添加到后台堆栈中,这非常耗费内存。
<强>更新强>: 由于您的要求不同。如您想要 Instagra 那样的标签,我希望此实施可以帮助您。
Deque<Integer> mStack = new ArrayDeque<>();
boolean isBackPressed = false;
private void setBottomNavigationView() {
mBottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.ic_home:
if(!isBackPressed) {
pushFragmentIntoStack(R.id.ic_home);
}
isBackPressed = false
setFragment(HomeFragment.newInstance(), HOME_FRAGMENT);
return true;
case R.id.ic_search:
if(!isBackPressed) {
pushFragmentIntoStack(R.id.ic_search);
}
isBackPressed = false
setFragment(SearchFragment.newInstance(), SEARCH_FRAGMENT);
return true;
case R.id.ic_circle:
if(!isBackPressed) {
pushFragmentIntoStack(R.id.ic_circle);
}
isBackPressed = false
setFragment(ShareFragment.newInstance(), SHARE_FRAGMENT);
return true;
default:
return false;
}
}
});
mBottomNavigationView.setOnNavigationItemReselectedListener(new
BottomNavigationView.OnNavigationItemReselectedListener() {
@Override
public void onNavigationItemReselected(@NonNull MenuItem item) {
}
});
mBottomNavigationView.setSelectedItemId(R.id.ic_home);
pushFragmentIntoStack(R.id.ic_home);
}
private void pushFragmentIntoStack(int id)
{
if(mStack.size() < 3)
{
mStack.push(id);
}
else
{
mStack.removeLast();
mStack.push(id);
}
}
private void setFragment(Fragment fragment, String tag) {
FragmentTransaction transaction = mFragmentManager.beginTransaction();
transaction.replace(R.id.container, fragment, tag);
transaction.commit();
}
@Override
public void onBackPressed() {
if(mStack.size() > 1)
{
isBackPressed = true;
mStack.pop();
mBottomNavigationView.setSelectedItemId(mStack.peek());
}
else
{
super.onBackPressed();
}
}
我使用deque来存储单击选项卡的顺序因为有3个选项卡deque size是3.在后面按它会弹出堆栈并转到该选项卡。如果堆栈中没有项目,它将退出活动。
重要提示: 在这种情况下,不要将片段添加到backstack,因为当我切换选项卡时,backstack计数将继续增加,甚至可能导致MemoryOutOfBound异常。
问题2: 来到你的Fragment标签问题,最好将标签保存在片段中。由于片段可以在任何活动中重复使用,而不是在每个使用它的活动中添加标记,所以如果我们将它添加到片段本身中就很好。
答案 1 :(得分:0)
尝试一下:
@Override
public void onBackPressed() {
if(navigation_bottom.getSelectedItemId () != R.id.action_home)
{
FragmentTransaction transaction =
((HomeActivity)this).getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.frameLayout_home, new HomeFragment());
transaction.commit();
navigation_bottom.setSelectedItemId(R.id.action_home);
}
else
{
HomeActivity.this.finishAffinity();
}
}
答案 2 :(得分:0)
您可以通过片段事务在后台添加片段名称
getFragmentManager()
.beginTransaction()
.replace(R.id.frame, YourCurrentFragment.newInstance())
.addToBackStack(YourFragment.class.getName())
.commit();
然后您可以添加onBackstackChangedListener以获得当前选定的片段
fragmentManager.addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
@Override
public void onBackStackChanged() {
FragmentManager.BackStackEntry bse = fragmentManager.
getBackStackEntryAt(fragmentManager.getBackStackEntryCount() -1);
//bse will be the backstack entry for current fragment
if (bse.getName().equals(YourFragment.class.getName())) {
navigationView.getMenu().getItem(0).setChecked(true);
} else if (bse.getName().equals(YourSecondFragment.class.getName())) {
navigationView.getMenu().getItem(1).setChecked(true);
}
}
});