重现的步骤:
BottomNavigationView
”:
将MainActivity替换为:
class MainActivity : AppCompatActivity() {
private var fragmentIds = ArrayList<Int>()
val fragmentA: FragmentA = FragmentA()
private val fragmentB = FragmentB()
private val fragmentC = FragmentC()
private fun getFragment(fragmentId: Int): Fragment {
when (fragmentId) {
R.id.navigation_home -> {
return fragmentA
}
R.id.navigation_dashboard -> {
return fragmentB
}
R.id.navigation_notifications -> {
return fragmentC
}
}
return fragmentA
}
private fun updateView(fragmentId: Int) {
var exists = false
fragmentIds
.filter { it == fragmentId }
.forEach { exists = true }
if (exists) {
fragmentIds.remove(fragmentId)
showTabWithoutAddingToBackStack(getFragment(fragmentId))
} else {
fragmentIds.add(fragmentId)
showTab(getFragment(fragmentId))
}
}
private val onNavigationItemClicked = BottomNavigationView.OnNavigationItemSelectedListener { item ->
when (item.itemId) {
R.id.navigation_home -> {
updateView(R.id.navigation_home)
return@OnNavigationItemSelectedListener true
}
R.id.navigation_dashboard -> {
updateView(R.id.navigation_dashboard)
return@OnNavigationItemSelectedListener true
}
R.id.navigation_notifications -> {
updateView(R.id.navigation_notifications)
return@OnNavigationItemSelectedListener true
}
}
false
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
showTabWithoutAddingToBackStack(fragmentA)
navigation.setOnNavigationItemSelectedListener(onNavigationItemClicked)
}
private fun showTab(fragment: Fragment) {
supportFragmentManager
.beginTransaction()
.replace(R.id.main_container, fragment, fragment::class.java.simpleName)
.addToBackStack(fragment::class.java.simpleName)
.commit()
}
fun showTabWithoutAddingToBackStack(fragment: Fragment) {
supportFragmentManager
.beginTransaction()
.replace(R.id.main_container, fragment, fragment::class.java.simpleName)
.commit()
}
fun setBottomTab(id: Int) {
navigation.setOnNavigationItemSelectedListener(null)
navigation.selectedItemId = id
// currentTab = id
navigation.setOnNavigationItemSelectedListener(onNavigationItemClicked)
}
}
创建3个新类,FragmentA,FragmentB和FragmentC:
class FragmentA : Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
setHasOptionsMenu(true)
return inflater.inflate(R.layout.fragment_a, container, false)
}
override fun onResume() {
super.onResume()
val act = activity as MainActivity
act.setBottomTab(R.id.navigation_home)
}
}
使用此xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Fragment A" />
</LinearLayout>
Here is a video that demonstrates above steps
堆栈跟踪:
12-06 12:58:35.899 25903-25903/com.example.jimclermonts.bottomnavigationview E/InputEventSender: Exception dispatching finished signal.
12-06 12:58:35.900 25903-25903/com.example.jimclermonts.bottomnavigationview E/MessageQueue-JNI: Exception in MessageQueue callback: handleReceiveCallback
12-06 12:58:35.912 25903-25903/com.example.jimclermonts.bottomnavigationview E/MessageQueue-JNI: java.lang.**IllegalStateException: Fragment already added**: FragmentB{3aac1d9 #1 id=0x7f080059 FragmentB}
at android.support.v4.app.FragmentManagerImpl.addFragment(FragmentManager.java:1882)
at android.support.v4.app.BackStackRecord.executePopOps(BackStackRecord.java:825)
at android.support.v4.app.FragmentManagerImpl.executeOps(FragmentManager.java:2577)
at android.support.v4.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2367)
at android.support.v4.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManager.java:2322)
at android.support.v4.app.FragmentManagerImpl.popBackStackImmediate(FragmentManager.java:851)
at android.support.v4.app.FragmentManagerImpl.popBackStackImmediate(FragmentManager.java:794)
at android.support.v4.app.FragmentActivity.onBackPressed(FragmentActivity.java:174)
答案 0 :(得分:3)
我使用Bottombar库实现了这个概念。我已经上传到GitHub了。如有任何问题,请在这里查看并发表评论。
示例输出
答案 1 :(得分:0)
这使您可以使用自定义后台堆栈(deque)进行“不要在backstack上重复(但重新排序)我的片段”行为:
class MainActivity extends AppCompatActivity {
private BottomNavigationView navigation;
// initialize with number of different fragments
private Deque<Integer> fragmentIds = new ArrayDeque<>(3);
private FragmentA fragmentA = new FragmentA();
private FragmentB fragmentB = new FragmentB();
private FragmentC fragmentC = new FragmentC();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
fragmentIds.push(R.id.navigation_home);
showTabWithoutAddingToBackStack(fragmentA);
navigation = findViewById(R.id.navigation);
navigation.setOnNavigationItemSelectedListener(onNavigationItemClicked);
}
private BottomNavigationView.OnNavigationItemSelectedListener onNavigationItemClicked = new BottomNavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
item.setChecked(true);
int itemId = item.getItemId();
if (fragmentIds.contains(itemId)) {
fragmentIds.remove(itemId);
}
fragmentIds.push(itemId);
showTabWithoutAddingToBackStack(getFragment(item.getItemId()));
return true;
}
};
private Fragment getFragment(int fragmentId) {
switch (fragmentId) {
case R.id.navigation_home:
return fragmentA;
case R.id.navigation_dashboard:
return fragmentB;
case R.id.navigation_notifications:
return fragmentC;
}
return fragmentA;
}
void showTabWithoutAddingToBackStack(Fragment fragment) {
getSupportFragmentManager().beginTransaction().replace(R.id.container, fragment, fragment.getClass().getSimpleName()).commit();
}
void setBottomTab(int id) {
int itemIndex;
switch (id) {
case R.id.navigation_dashboard:
itemIndex = 1;
break;
case R.id.navigation_notifications:
itemIndex = 2;
break;
default:
case R.id.navigation_home:
itemIndex = 0;
}
navigation.getMenu().getItem(itemIndex).setChecked(true);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) {
onBackPressed();
return true;
}
return super.onKeyDown(keyCode, event);
}
@Override
public void onBackPressed() {
fragmentIds.pop();
if (!fragmentIds.isEmpty()) {
showTabWithoutAddingToBackStack(getFragment(fragmentIds.peek()));
} else {
finish();
}
}
}
答案 2 :(得分:0)
我必须稍微更改它并让它工作,我已经测试了多个设备并在一次测试运行中切换标签超过100次。 它工作正常,更改代码,
private fun updateView(fragmentId: Int) {
var exists = false
fragmentIds
.filter { it == fragmentId }
.forEach { exists = true }
if (exists) {
fragmentIds.remove(fragmentId)
showTabWithoutAddingToBackStack(getFragment(fragmentId))
} else {
fragmentIds.add(fragmentId)
showTab(getFragment(fragmentId))
}
}
到这个新代码,
private fun updateView(fragmentId: Int) {
var exists = false
fragmentIds
.filter { it == fragmentId }
.forEach { exists = true }
if (exists) {
showTab(getFragment(fragmentId))
setBottomTab(fragmentId)
} else {
fragmentIds.add(fragmentId)
showTab(getFragment(fragmentId))
}
}
就是这样!!!
答案 3 :(得分:0)
您好,请检查是否已完成并正常工作。 您可以检查一下。 https://github.com/sandeshsk/BackStackFragmentRedirectsToHome
如果有任何问题,请更新。
这是分配片段的方法
public void addFragment(FragmentManager fragmentManager,
Fragment fragment,
int containerId,boolean isFromHome){
fragmentManager.popBackStack(null,FragmentManager.POP_BACK_STACK_INCLUSIVE);
FragmentTransaction fragmentTransaction=fragmentManager.beginTransaction();
if(isFromHome){
fragmentTransaction.replace(containerId,fragment);
}else{
fragmentTransaction.add(new HomeFragment(),"Home");
fragmentTransaction.addToBackStack("Home");
}
fragmentTransaction.replace(containerId,fragment).commit();
}
这是您的导航项目侦听器
private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
= new BottomNavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.navigation_home:
if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
addFragment(getSupportFragmentManager(), new HomeFragment(), R.id.frame, true);
}else{
getSupportFragmentManager().popBackStack();
}
return true;
case R.id.navigation_dashboard:
addFragment(getSupportFragmentManager(),new DashboardFragment(),R.id.frame,false);
return true;
case R.id.navigation_notifications:
addFragment(getSupportFragmentManager(),new NotificationFragment(),R.id.frame,false);
return true;
case R.id.navigation_setting:
addFragment(getSupportFragmentManager(),new SettingFragment(),R.id.frame,false);
return true;
}
return false;
}
};
onBackPressed方法
@Override
public void onBackPressed() {
if(getSupportFragmentManager().getBackStackEntryCount()>0){
navigation.setSelectedItemId(R.id.navigation_home);
}else {
super.onBackPressed();
}
}
答案 4 :(得分:-1)
如果您想返回堆栈中的所有项目(不仅是首页),例如Youtube,请尝试以下代码:
BottomNavigationView bottomNavigationView;
FragmentTransaction transaction;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
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.action_item1:
selectedFragment = ItemOneFragment.newInstance();
break;
case R.id.action_item2:
selectedFragment = ItemTwoFragment.newInstance();
break;
case R.id.action_item3:
selectedFragment = ItemThreeFragment.newInstance();
break;
case R.id.action_item4:
selectedFragment = ItemFourFragment.newInstance();
break;
case R.id.action_item5:
selectedFragment = ItemFiveFragment.newInstance();
break;
}
transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.frame_layout, selectedFragment);
transaction.addToBackStack(null);
transaction.commit();
return true;
}
});
//Manually displaying the first fragment - one time only
transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.frame_layout, ItemOneFragment.newInstance());
transaction.commit();
}
@Override
public void onBackPressed() {
int count = getSupportFragmentManager().getBackStackEntryCount();
if (count == 0) {
super.onBackPressed();
} else {
int index = ((getSupportFragmentManager().getBackStackEntryCount()) -1);
getSupportFragmentManager().popBackStack();
FragmentManager.BackStackEntry backEntry = getSupportFragmentManager().getBackStackEntryAt(index);
int stackId = backEntry.getId();
bottomNavigationView.getMenu().getItem(stackId).setChecked(true);
}
}