BottomNavigationView - 如何避免重新创建片段并重用它们
BottomNavigationView - How to avoid recreation of Fragments and reuse them
我想在我的项目中做一个底部导航栏。每个视图都有自己的片段。问题是,每次我点击按钮更改视图,例如从最近到收藏夹,它都会创建具有全新状态的新片段(例如,滚动位置,无论我的片段包含什么,文本都会改变)。我知道在官方 Android 文档中写到底部导航栏应该重置任务状态,但我认为这对用户来说太不舒服了。
我想拥有类似 instagram 的功能,您可以从提要更改为探索,然后返回到提要滚动位置图像缓存所有内容都保留下来。我几乎尝试了所有方法来解决这个问题,唯一有效的方法是根据情况设置可见性 GONE 和设置可见性 VISIBLE,但我知道这不是正确的方法,应该有更好的方法,我不是在谈论手动保存需要的实例。我几乎遵循了所有关于底部导航片段的教程,但有趣的是,没有人有兴趣在每次不调用 new 的情况下使用它。
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.frameLayout, FirstFragment.newInstance());
fragmentTransaction.commit();
bottomNavigationView = (BottomNavigationView) findViewById(R.id.navigation);
bottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
Fragment fragment = null;
switch (item.getItemId()) {
case R.id.menu_dialer:
fragment = FirstFragment.newInstance();
break;
case R.id.menu_email:
fragment = SecondFragment.newInstance();
break;
case R.id.menu_map:
fragment = ThirdFragment.newInstance();
break;
}
if (fragment != null) {
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.frameLayout, fragment);
fragmentTransaction.commit();
}
return true;
}
});
我也尝试了 onAttach 和 Deattach 解决方案,但还是没有成功。
VIDEO LINK : new i tried Nino Handler version it only works when i tap on the same fragment button
可能与我使用的金丝雀版本有关,或者我的 gradle 依赖项有问题?
新更新:
public class MainActivity extends AppCompatActivity {
private TextView mTextMessage;
private static final String TAG_FRAGMENT_ONE = "fragment_one";
private static final String TAG_FRAGMENT_TWO = "fragment_two";
private FragmentManager fragmentManager;
private Fragment currentFragment;
String TAG = "babken";
private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
= new BottomNavigationView.OnNavigationItemSelectedListener() {
Fragment fragment = null;
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.navigation_home:
fragment = fragmentManager.findFragmentByTag(TAG_FRAGMENT_ONE);
if (fragment == null) {
fragment = FragmentFirst.newInstance();
}
replaceFragment(fragment, TAG_FRAGMENT_ONE);
break;
case R.id.navigation_dashboard:
fragment = fragmentManager.findFragmentByTag(TAG_FRAGMENT_TWO);
if (fragment == null) {
fragment = FragmentSecond.newInstance();
}
replaceFragment(fragment, TAG_FRAGMENT_TWO);
break;
}
return true;
}
};
private void replaceFragment(@NonNull Fragment fragment, @NonNull String tag) {
if (!fragment.equals(currentFragment)) {
fragmentManager
.beginTransaction()
.replace(R.id.armen, fragment, tag)
.commit();
currentFragment = fragment;
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
fragmentManager = getSupportFragmentManager();
Fragment fragment = fragmentManager.findFragmentByTag(TAG_FRAGMENT_ONE);
if (fragment == null) {
fragment = FragmentFirst.newInstance();
}
replaceFragment(fragment, TAG_FRAGMENT_ONE);
BottomNavigationView navigation = (BottomNavigationView) findViewById(R.id.navigation);
navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
}
}
怎么样。
您在 class.
中声明片段
Fragment firstFragment,secondFragment,thirdFragment;
然后在 switch-case 你可以这样编码:
switch (item.getItemId()) {
case R.id.menu_dialer:
if(firstFragment != null) {
fragment = firstFragment;
}else{
fragment = FirstFragment.newInstance();
}
break;
case R.id.menu_email:
// the same ...
break;
case R.id.menu_map:
//the same ...
break;
}
创建三个片段作为 class 的成员并重新使用它们。
public class MainActivity extends AppCompatActivity {
private final Fragment mFirstFragment = new FirstFragment();
private final Fragment mSecondFragment = new SecondFragment();
private final Fragment mThirdFragment = new ThirdFragment();
@Override
protected void onCreate(Bundle savedInstanceState) {
......
......
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.frameLayout, mFirstFragment);
fragmentTransaction.commit();
bottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
if (bottomNavigationView.getSelectedItemId() != item.getItemId()) {
switch (item.getItemId()) {
R.id.menu_dialer:
replaceFragment(mFirstFragment);
break;
case R.id.menu_email:
replaceFragment(mSecondFragment);
break;
case R.id.menu_map:
replaceFragment(mThirdFragment);
break;
}
}
return true;
}
});
}
private void replaceFragment(Fragment fragment) {
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.frameLayout, fragment);
fragmentTransaction.commit();
}
}
我不会全局保留片段实例。
而是在创建它们时向片段添加标签
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.container, new PlaceholderFragment(), TAG_PLACEHOLDER)
.commit();
然后你总是可以像这样检索它:
Fragment fragment = getSupportFragmentManager().findFragmentByTag(TAG_PLACEHOLDER);
if (fragment == null) {
fragment = new PlaceholderFragment();
}
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.container, fragment, TAG_PLACEHOLDER)
.commit();
更新:我更新了我的答案并提供了一个完整的解决方案:
private static final String TAG_FRAGMENT_ONE = "fragment_one";
private static final String TAG_FRAGMENT_TWO = "fragment_two";
private static final String TAG_FRAGMENT_THREE = "fragment_three";
private FragmentManager fragmentManager;
private Fragment currentFragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// instantiate the fragment manager
fragmentManager = getSupportFragmentManager();
Fragment fragment = fragmentManager.findFragmentByTag(TAG_FRAGMENT_ONE);
if (fragment == null) {
fragment = FirstFragment.newInstance();
}
replaceFragment(fragment, TAG_FRAGMENT_ONE);
bottomNavigationView = (BottomNavigationView) findViewById(R.id.navigation);
bottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
Fragment fragment = null;
switch (item.getItemId()) {
case R.id.menu_dialer:
// I'm aware that this code can be optimized by a method which accepts a class definition and returns the proper fragment
Fragment fragment = fragmentManager.findFragmentByTag(TAG_FRAGMENT_ONE);
if (fragment == null) {
fragment = FirstFragment.newInstance();
}
replaceFragment(fragment, TAG_FRAGMENT_ONE);
break;
case R.id.menu_email:
Fragment fragment = fragmentManager.findFragmentByTag(TAG_FRAGMENT_TWO);
if (fragment == null) {
fragment = SecondFragment.newInstance();
}
replaceFragment(fragment, TAG_FRAGMENT_TWO);
break;
case R.id.menu_map:
Fragment fragment = fragmentManager.findFragmentByTag(TAG_FRAGMENT_THREE);
if (fragment == null) {
fragment = ThirdFragment.newInstance();
}
replaceFragment(fragment, TAG_FRAGMENT_THREE);
break;
}
return true;
}
});
}
private void replaceFragment(@NonNull Fragment fragment, @NonNull String tag) {
if (!fragment.equals(currentFragment)) {
fragmentManager
.beginTransaction()
.replace(R.id.frameLayout, fragment, tag)
.commit();
currentFragment = fragment;
}
}
附加信息:如果您想确保片段状态不会改变,并且如果您还希望能够滑动片段,您应该考虑使用 ViewPager with a FragmentStatePagerAdapter 并更改当前片段每次点击事件的适配器
所以我为此研究了很长时间,发现没有办法重用自动保存状态的片段,你必须手动保存你需要的状态,然后在创建新片段时检索它们,但是什么关于滚动位置它太难了,甚至在某些情况下无法保存滚动视图位置状态(例如回收视图)。因此,当我单击片段变得可见的按钮时,我使用了称为 VISIBILITY 的概念,其他片段会自动隐藏。
之前的回答都是用fragmentTransaction.replace(...)
。这将通过销毁它来替换当前片段(这是导致问题的原因)。因此,所有这些解决方案实际上都行不通。
这是我能找到的最接近这个问题的解决方案:
private void selectContentFragment(Fragment fragmentToSelect)
{
FragmentTransaction fragmentTransaction = this.getSupportFragmentManager().beginTransaction();
if (this.getSupportFragmentManager().getFragments().contains(fragmentToSelect)) {
// Iterate through all cached fragments.
for (Fragment cachedFragment : this.getSupportFragmentManager().getFragments()) {
if (cachedFragment != fragmentToSelect) {
// Hide the fragments that are not the one being selected.
fragmentTransaction.hide(cachedFragment);
}
}
// Show the fragment that we want to be selected.
fragmentTransaction.show(fragmentToSelect);
} else {
// The fragment to be selected does not (yet) exist in the fragment manager, add it.
fragmentTransaction.add(R.id.fragment_container, fragmentToSelect);
}
fragmentTransaction.commit();
}
要完成这项工作,您应该在 Activity 中跟踪数组(或单独变量)中的片段。我参考 pre-instantiated SparseArray 中的所有片段。
我遇到了类似的问题,但这段代码解决了我的问题。
public class MainActivity extends AppCompatActivity {
boolean doubleBackToExitPressedOnce = false;
final Fragment fragment1 = new HomeFragment();
final Fragment fragment2 = new DashboardFragment();
final Fragment fragment3 = new NotificationsFragment();
final FragmentManager fm = getSupportFragmentManager();
Fragment active = fragment1;
BottomNavigationView navigation;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
navigation = (BottomNavigationView) findViewById(R.id.navigation);
navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
setFragment(fragment1, "1", 0);
}
private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
= new BottomNavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.navigation_home:
setFragment(fragment1, "1", 0);
return true;
case R.id.navigation_dashboard:
setFragment(fragment2, "2", 1);
return true;
case R.id.navigation_notifications:
setFragment(fragment3, "3", 2);
return true;
}
return false;
}
};
public void setFragment(Fragment fragment, String tag, int position) {
if (fragment.isAdded()) {
fm.beginTransaction().hide(active).show(fragment).commit();
} else {
fm.beginTransaction().add(R.id.main_container, fragment, tag).commit();
}
navigation.getMenu().getItem(position).setChecked(true);
active = fragment;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main_menu, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_settings) {
startActivity(new Intent(MainActivity.this, SettingsActivity.class));
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onBackPressed() {
if (active == fragment1) {
if (doubleBackToExitPressedOnce) {
super.onBackPressed();
return;
}
this.doubleBackToExitPressedOnce = true;
Toast.makeText(this, "Please click BACK again to exit", Toast.LENGTH_SHORT).show();
} else {
setFragment(fragment1, "1", 0);
}
}
}
您可以使用 attach() 和 detach() 方法:
private FirstFragment firstFragment = FirstFragment.newInstance();
private SecondFragment secondFragment= SecondFragment.newInstance();
private ThirdFragment thirdFragment = ThirdFragment.newInstance();
navigation.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_dialer:
changeFragment(firstFragment, "firstFragment");
return true;
case R.id.menu_email:
changeFragment(secondFragment, "secondFragment");
return true;
case R.id.menu_map:
changeFragment(thirdFragment, "thirdFragment");
return true;
}
return false;
}
});
public void changeFragment(Fragment fragment, String tagFragmentName) {
FragmentManager mFragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
Fragment currentFragment = mFragmentManager.getPrimaryNavigationFragment();
if (currentFragment != null) {
fragmentTransaction.detach(currentFragment);
}
Fragment fragmentTemp = mFragmentManager.findFragmentByTag(tagFragmentName);
if (fragmentTemp == null) {
fragmentTemp = fragment;
fragmentTransaction.add(R.id.content, fragmentTemp, tagFragmentName);
} else {
fragmentTransaction.attach(fragmentTemp);
}
fragmentTransaction.setPrimaryNavigationFragment(fragmentTemp);
fragmentTransaction.setReorderingAllowed(true);
fragmentTransaction.commitNowAllowingStateLoss();
}
我为 FragmentManager 写了一个 Kotlin 扩展函数 class
fun FragmentManager.switch(containerId: Int, newFrag: Fragment, tag: String) {
var current = findFragmentByTag(tag)
beginTransaction()
.apply {
//Hide the current fragment
primaryNavigationFragment?.let { hide(it) }
//Check if current fragment exists in fragmentManager
if (current == null) {
current = newFrag
add(containerId, current!!, tag)
} else {
show(current!!)
}
}
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
.setPrimaryNavigationFragment(current)
.setReorderingAllowed(true)
.commitNowAllowingStateLoss()
}
这可以由 supportFragmentManager.swtich(R.id.container,newFrag,newFrag.TAG)
从 onNavigationItemSelected
调用
Thomas 的回答几乎帮助了我,但有一个问题,每当我第一次打开新片段时,它们会重叠,但一旦我按下菜单按钮再次打开它们就不会重叠。
于是我修改了他的代码,使用如下代码得到了解决方案:
private fun selectContentFragment(fragmentToSelect: Fragment) {
val fragmentTransaction = fragmentManager?.beginTransaction()
if (fragmentManager?.fragments?.contains(fragmentToSelect)!!) {
// Show the fragment that we want to be selected.
fragmentTransaction?.show(fragmentToSelect)
} else {
// The fragment to be selected does not (yet) exist in the fragment manager, add it.
fragmentTransaction?.add(R.id.container, fragmentToSelect)
}
// Iterate through all cached fragments.
for (cachedFragment in fragmentManager?.fragments!!) {
if (cachedFragment !== fragmentToSelect) {
// Hide the fragments that are not the one being selected.
// Uncomment following line and change the name of the fragment if your host isn't an activity and a fragment otherwise whole view will get hidden.
// if (!cachedFragment.toString().contains("HomeContainerFragment"))
fragmentTransaction?.hide(cachedFragment)
}
}
fragmentTransaction?.commit()
}
确保您不会每次都传递片段的新实例。
这行得通:
selectContentFragment(
when (item.itemId) {
R.id.home -> frag1
R.id.photoGallery -> frag2
else -> Home()
}
)
其中 frag1
和 frag2
是全局变量,定义为:
val frag1 = Home()
val frag2 = PhotoGallery()
这行不通:
selectContentFragment(
when (item.itemId) {
R.id.home -> Home()
R.id.photoGallery -> PhotoGallery()
else -> Home()
}
)
浪费了我好几个小时。希望对大家有帮助!
**这段代码对我很有帮助。就像优酷一样。 **
private Deque<Integer> fragmentIds = new ArrayDeque<>(3);
int itemId;
private HomeFragment homeFragment = new HomeFragment();
private FavouriteFragment favouriteFragment = new FavouriteFragment();
private NearmeFragment nearmeFragment = new NearmeFragment();
BottomNavigationView bottomNavigationView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
fragmentIds.push(R.id.action_home);
showTabWithoutAddingToBackStack(homeFragment);
bottomNavigationView = findViewById(R.id.bottom_navigation);
bottomNavigationView.setOnNavigationItemSelectedListener(onNavigationItemClicked);
}
private BottomNavigationView.OnNavigationItemSelectedListener onNavigationItemClicked = new BottomNavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
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.action_home:
return homeFragment;
case R.id.action_favorites:
return favouriteFragment;
case R.id.action_nearme:
return nearmeFragment;
}
return homeFragment;
}
private void showTabWithoutAddingToBackStack(Fragment fragment) {
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, fragment, fragment.getClass().getSimpleName()).commit();
}
@Override
public void onBackPressed() {
if(fragmentIds.getLast() != R.id.action_home){
fragmentIds.addLast(R.id.action_home);
}
fragmentIds.pop();
bottomNavigationView.getMenu().getItem(fragmentIds.size()-1).setChecked(true);
if (!fragmentIds.isEmpty()) {
showTabWithoutAddingToBackStack(getFragment(fragmentIds.peek()));
} else {
finish();
}
}
对于 Kotlin 用户可以帮助此代码:
首先创建一个FragmentManager扩展class
fun FragmentManager.replace(containerId: Int, fragment: Fragment, tag: String) {
var current = findFragmentByTag(tag)
beginTransaction()
.apply {
//Hide the current fragment
primaryNavigationFragment?.let { hide(it) }
//Check if current fragment exists in fragmentManager
if (current == null) {
current = fragment
add(containerId, current!!, tag)
} else {
show(current!!)
}
}
.setTransition(FragmentTransaction.TRANSIT_ENTER_MASK)
.setPrimaryNavigationFragment(current)
.setReorderingAllowed(true)
.commitNowAllowingStateLoss()
}
现在只需在您的
上调用它
onNavigationItemSelected
supportFragmentManager.replace(R.id.fragment_id,YourFragmentClass,yourFragment.TAG)
我有同样的问题,但我通过创建多个片段主机解决了它,然后我在 fragmentHost 中添加了片段。当底部导航 itemSelected 时,我只是使所需的主机片段可见,而其他主机片段主机可见性消失了。
这个方法可能有误,但对我来说很管用。
而且我们不必手动处理片段的状态,只需要处理 activity 的背压。
但是这个方法不会暂停片段。
而且我不知道如何处理片段的暂停和恢复所以请回复我。
也许这会对你有所帮助。
这是我的 fragmentHosts 主页 Activity:
<androidx.fragment.app.FragmentContainerView
android:id="@+id/homeFragmentHost"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@+id/bottom_NavBar"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:visibility="gone"/>
<androidx.fragment.app.FragmentContainerView
android:id="@+id/libraryFragmentHost"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@+id/bottom_NavBar"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:visibility="gone"/>
<androidx.fragment.app.FragmentContainerView
android:id="@+id/myStuffFragmentHost"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@+id/bottom_NavBar"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:visibility="gone"/>
<androidx.fragment.app.FragmentContainerView
android:id="@+id/moreFragmentHost"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@+id/bottom_NavBar"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:visibility="gone"/>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/bottom_NavBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:menu="@menu/app_bottom_nav_menu"
tools:ignore="BottomAppBar" />
首页Activity onCreate:
supportFragmentManager.beginTransaction().replace(R.id.homeFragmentHost,HomeFragment()).commitNow()
supportFragmentManager.beginTransaction().replace(R.id.libraryFragmentHost,LibraryFragment()).commitNow()
supportFragmentManager.beginTransaction().replace(R.id.myStuffFragmentHost,MyStuffFragment()).commitNow()
supportFragmentManager.beginTransaction().replace(R.id.moreFragmentHost,MoreFragment()).commitNow()
homeFragmentHost.visibility = View.VISIBLE
底部导航项目选定的侦听器
override fun onNavigationItemSelected(item: MenuItem): Boolean {
return when(item.itemId){
R.id.homeFragment -> loadFragmentHost(homeFragmentHost)
R.id.libraryFragment -> loadFragmentHost(libraryFragmentHost)
R.id.myStuffFragment -> loadFragmentHost(myStuffFragmentHost)
R.id.moreFragment -> loadFragmentHost(moreFragmentHost)
else -> false
}
loadFragmentHost 函数
private fun loadFragmentHost(view:FragmentContainerView): Boolean {
val list = arrayListOf(homeFragmentHost,libraryFragmentHost,myStuffFragmentHost,moreFragmentHost)
list.remove(view)
view.visibility = View.VISIBLE
list.forEach {
it.visibility = View.GONE
}
return true
}
public class MainActivity extends AppCompatActivity {
boolean doubleBackToExitPressedOnce = false;
final Fragment fragment1 = new HomeFragment();
final Fragment fragment2 = new DashboardFragment();
final Fragment fragment3 = new NotificationsFragment();
final FragmentManager fm = getSupportFragmentManager();
Fragment active = fragment1;
BottomNavigationView navigation;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
navigation = (BottomNavigationView) findViewById(R.id.navigation);
navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
setFragment(fragment1, "1", 0);
}
private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
= new BottomNavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.navigation_home:
setFragment(fragment1, "1", 0);
return true;
case R.id.navigation_dashboard:
setFragment(fragment2, "2", 1);
return true;
case R.id.navigation_notifications:
setFragment(fragment3, "3", 2);
return true;
}
return false;
}
};
public void setFragment(Fragment fragment, String tag, int position) {
if (fragment.isAdded()) {
fm.beginTransaction().hide(active).show(fragment).commit();
} else {
fm.beginTransaction().add(R.id.main_container, fragment, tag).commit();
}
navigation.getMenu().getItem(position).setChecked(true);
active = fragment;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main_menu, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_settings) {
startActivity(new Intent(MainActivity.this, SettingsActivity.class));
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onBackPressed() {
if (active == fragment1) {
if (doubleBackToExitPressedOnce) {
super.onBackPressed();
return;
}
this.doubleBackToExitPressedOnce = true;
Toast.makeText(this, "Please click BACK again to exit", Toast.LENGTH_SHORT).show();
} else {
setFragment(fragment1, "1", 0);
}
}
}
- 维护底部sheet片段
Reusable
- BackPress 维护
- 双击退出
public class MainActivity extends AppCompatActivity {
BottomNavigationView bottomNavigationView;
Toaster toaster;
private final Fragment androidFragment = new AndroidFragment();
private final Fragment settingsFragment = new SettingsFragment();
Fragment active;
String TAG = MainActivity.class.getSimpleName();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
toaster = new Toaster(this);
bottomNavigationView = findViewById(R.id.bottom_navigation);
renderFragment(androidFragment, "android");
active = androidFragment;
bottomNavigationView.setOnItemSelectedListener(
item -> {
Log.e(TAG, "onCreate: " + active );
if(item.getItemId() == R.id.action_android){
renderFragment(androidFragment, "android");
return true;
}
else if(item.getItemId() == R.id.action_settings){
renderFragment(settingsFragment, "settings");
return true;
}
return false;
}
);
}
private void renderFragment(Fragment fragment, String tag){
FragmentManager fragmentManager = getSupportFragmentManager();
if(fragment.isAdded()){
fragmentManager.beginTransaction().hide(active).show(fragment)
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN).commit();
}
else {
if(active != null){
getSupportFragmentManager().beginTransaction()
.add(R.id.fragment_container_view, fragment, tag)
.hide(active)
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN).commit();
}
else {
getSupportFragmentManager().beginTransaction()
.add(R.id.fragment_container_view, fragment, tag)
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN).commit();
}
}
active = fragment;
}
}
伙计们,这对我有用。
我想在我的项目中做一个底部导航栏。每个视图都有自己的片段。问题是,每次我点击按钮更改视图,例如从最近到收藏夹,它都会创建具有全新状态的新片段(例如,滚动位置,无论我的片段包含什么,文本都会改变)。我知道在官方 Android 文档中写到底部导航栏应该重置任务状态,但我认为这对用户来说太不舒服了。 我想拥有类似 instagram 的功能,您可以从提要更改为探索,然后返回到提要滚动位置图像缓存所有内容都保留下来。我几乎尝试了所有方法来解决这个问题,唯一有效的方法是根据情况设置可见性 GONE 和设置可见性 VISIBLE,但我知道这不是正确的方法,应该有更好的方法,我不是在谈论手动保存需要的实例。我几乎遵循了所有关于底部导航片段的教程,但有趣的是,没有人有兴趣在每次不调用 new 的情况下使用它。
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.frameLayout, FirstFragment.newInstance());
fragmentTransaction.commit();
bottomNavigationView = (BottomNavigationView) findViewById(R.id.navigation);
bottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
Fragment fragment = null;
switch (item.getItemId()) {
case R.id.menu_dialer:
fragment = FirstFragment.newInstance();
break;
case R.id.menu_email:
fragment = SecondFragment.newInstance();
break;
case R.id.menu_map:
fragment = ThirdFragment.newInstance();
break;
}
if (fragment != null) {
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.frameLayout, fragment);
fragmentTransaction.commit();
}
return true;
}
});
我也尝试了 onAttach 和 Deattach 解决方案,但还是没有成功。
VIDEO LINK : new i tried Nino Handler version it only works when i tap on the same fragment button
可能与我使用的金丝雀版本有关,或者我的 gradle 依赖项有问题?
新更新:
public class MainActivity extends AppCompatActivity {
private TextView mTextMessage;
private static final String TAG_FRAGMENT_ONE = "fragment_one";
private static final String TAG_FRAGMENT_TWO = "fragment_two";
private FragmentManager fragmentManager;
private Fragment currentFragment;
String TAG = "babken";
private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
= new BottomNavigationView.OnNavigationItemSelectedListener() {
Fragment fragment = null;
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.navigation_home:
fragment = fragmentManager.findFragmentByTag(TAG_FRAGMENT_ONE);
if (fragment == null) {
fragment = FragmentFirst.newInstance();
}
replaceFragment(fragment, TAG_FRAGMENT_ONE);
break;
case R.id.navigation_dashboard:
fragment = fragmentManager.findFragmentByTag(TAG_FRAGMENT_TWO);
if (fragment == null) {
fragment = FragmentSecond.newInstance();
}
replaceFragment(fragment, TAG_FRAGMENT_TWO);
break;
}
return true;
}
};
private void replaceFragment(@NonNull Fragment fragment, @NonNull String tag) {
if (!fragment.equals(currentFragment)) {
fragmentManager
.beginTransaction()
.replace(R.id.armen, fragment, tag)
.commit();
currentFragment = fragment;
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
fragmentManager = getSupportFragmentManager();
Fragment fragment = fragmentManager.findFragmentByTag(TAG_FRAGMENT_ONE);
if (fragment == null) {
fragment = FragmentFirst.newInstance();
}
replaceFragment(fragment, TAG_FRAGMENT_ONE);
BottomNavigationView navigation = (BottomNavigationView) findViewById(R.id.navigation);
navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
}
}
怎么样。 您在 class.
中声明片段Fragment firstFragment,secondFragment,thirdFragment;
然后在 switch-case 你可以这样编码:
switch (item.getItemId()) {
case R.id.menu_dialer:
if(firstFragment != null) {
fragment = firstFragment;
}else{
fragment = FirstFragment.newInstance();
}
break;
case R.id.menu_email:
// the same ...
break;
case R.id.menu_map:
//the same ...
break;
}
创建三个片段作为 class 的成员并重新使用它们。
public class MainActivity extends AppCompatActivity {
private final Fragment mFirstFragment = new FirstFragment();
private final Fragment mSecondFragment = new SecondFragment();
private final Fragment mThirdFragment = new ThirdFragment();
@Override
protected void onCreate(Bundle savedInstanceState) {
......
......
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.frameLayout, mFirstFragment);
fragmentTransaction.commit();
bottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
if (bottomNavigationView.getSelectedItemId() != item.getItemId()) {
switch (item.getItemId()) {
R.id.menu_dialer:
replaceFragment(mFirstFragment);
break;
case R.id.menu_email:
replaceFragment(mSecondFragment);
break;
case R.id.menu_map:
replaceFragment(mThirdFragment);
break;
}
}
return true;
}
});
}
private void replaceFragment(Fragment fragment) {
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.frameLayout, fragment);
fragmentTransaction.commit();
}
}
我不会全局保留片段实例。 而是在创建它们时向片段添加标签
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.container, new PlaceholderFragment(), TAG_PLACEHOLDER)
.commit();
然后你总是可以像这样检索它:
Fragment fragment = getSupportFragmentManager().findFragmentByTag(TAG_PLACEHOLDER);
if (fragment == null) {
fragment = new PlaceholderFragment();
}
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.container, fragment, TAG_PLACEHOLDER)
.commit();
更新:我更新了我的答案并提供了一个完整的解决方案:
private static final String TAG_FRAGMENT_ONE = "fragment_one";
private static final String TAG_FRAGMENT_TWO = "fragment_two";
private static final String TAG_FRAGMENT_THREE = "fragment_three";
private FragmentManager fragmentManager;
private Fragment currentFragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// instantiate the fragment manager
fragmentManager = getSupportFragmentManager();
Fragment fragment = fragmentManager.findFragmentByTag(TAG_FRAGMENT_ONE);
if (fragment == null) {
fragment = FirstFragment.newInstance();
}
replaceFragment(fragment, TAG_FRAGMENT_ONE);
bottomNavigationView = (BottomNavigationView) findViewById(R.id.navigation);
bottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
Fragment fragment = null;
switch (item.getItemId()) {
case R.id.menu_dialer:
// I'm aware that this code can be optimized by a method which accepts a class definition and returns the proper fragment
Fragment fragment = fragmentManager.findFragmentByTag(TAG_FRAGMENT_ONE);
if (fragment == null) {
fragment = FirstFragment.newInstance();
}
replaceFragment(fragment, TAG_FRAGMENT_ONE);
break;
case R.id.menu_email:
Fragment fragment = fragmentManager.findFragmentByTag(TAG_FRAGMENT_TWO);
if (fragment == null) {
fragment = SecondFragment.newInstance();
}
replaceFragment(fragment, TAG_FRAGMENT_TWO);
break;
case R.id.menu_map:
Fragment fragment = fragmentManager.findFragmentByTag(TAG_FRAGMENT_THREE);
if (fragment == null) {
fragment = ThirdFragment.newInstance();
}
replaceFragment(fragment, TAG_FRAGMENT_THREE);
break;
}
return true;
}
});
}
private void replaceFragment(@NonNull Fragment fragment, @NonNull String tag) {
if (!fragment.equals(currentFragment)) {
fragmentManager
.beginTransaction()
.replace(R.id.frameLayout, fragment, tag)
.commit();
currentFragment = fragment;
}
}
附加信息:如果您想确保片段状态不会改变,并且如果您还希望能够滑动片段,您应该考虑使用 ViewPager with a FragmentStatePagerAdapter 并更改当前片段每次点击事件的适配器
所以我为此研究了很长时间,发现没有办法重用自动保存状态的片段,你必须手动保存你需要的状态,然后在创建新片段时检索它们,但是什么关于滚动位置它太难了,甚至在某些情况下无法保存滚动视图位置状态(例如回收视图)。因此,当我单击片段变得可见的按钮时,我使用了称为 VISIBILITY 的概念,其他片段会自动隐藏。
之前的回答都是用fragmentTransaction.replace(...)
。这将通过销毁它来替换当前片段(这是导致问题的原因)。因此,所有这些解决方案实际上都行不通。
这是我能找到的最接近这个问题的解决方案:
private void selectContentFragment(Fragment fragmentToSelect)
{
FragmentTransaction fragmentTransaction = this.getSupportFragmentManager().beginTransaction();
if (this.getSupportFragmentManager().getFragments().contains(fragmentToSelect)) {
// Iterate through all cached fragments.
for (Fragment cachedFragment : this.getSupportFragmentManager().getFragments()) {
if (cachedFragment != fragmentToSelect) {
// Hide the fragments that are not the one being selected.
fragmentTransaction.hide(cachedFragment);
}
}
// Show the fragment that we want to be selected.
fragmentTransaction.show(fragmentToSelect);
} else {
// The fragment to be selected does not (yet) exist in the fragment manager, add it.
fragmentTransaction.add(R.id.fragment_container, fragmentToSelect);
}
fragmentTransaction.commit();
}
要完成这项工作,您应该在 Activity 中跟踪数组(或单独变量)中的片段。我参考 pre-instantiated SparseArray 中的所有片段。
我遇到了类似的问题,但这段代码解决了我的问题。
public class MainActivity extends AppCompatActivity {
boolean doubleBackToExitPressedOnce = false;
final Fragment fragment1 = new HomeFragment();
final Fragment fragment2 = new DashboardFragment();
final Fragment fragment3 = new NotificationsFragment();
final FragmentManager fm = getSupportFragmentManager();
Fragment active = fragment1;
BottomNavigationView navigation;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
navigation = (BottomNavigationView) findViewById(R.id.navigation);
navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
setFragment(fragment1, "1", 0);
}
private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
= new BottomNavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.navigation_home:
setFragment(fragment1, "1", 0);
return true;
case R.id.navigation_dashboard:
setFragment(fragment2, "2", 1);
return true;
case R.id.navigation_notifications:
setFragment(fragment3, "3", 2);
return true;
}
return false;
}
};
public void setFragment(Fragment fragment, String tag, int position) {
if (fragment.isAdded()) {
fm.beginTransaction().hide(active).show(fragment).commit();
} else {
fm.beginTransaction().add(R.id.main_container, fragment, tag).commit();
}
navigation.getMenu().getItem(position).setChecked(true);
active = fragment;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main_menu, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_settings) {
startActivity(new Intent(MainActivity.this, SettingsActivity.class));
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onBackPressed() {
if (active == fragment1) {
if (doubleBackToExitPressedOnce) {
super.onBackPressed();
return;
}
this.doubleBackToExitPressedOnce = true;
Toast.makeText(this, "Please click BACK again to exit", Toast.LENGTH_SHORT).show();
} else {
setFragment(fragment1, "1", 0);
}
}
}
您可以使用 attach() 和 detach() 方法:
private FirstFragment firstFragment = FirstFragment.newInstance();
private SecondFragment secondFragment= SecondFragment.newInstance();
private ThirdFragment thirdFragment = ThirdFragment.newInstance();
navigation.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_dialer:
changeFragment(firstFragment, "firstFragment");
return true;
case R.id.menu_email:
changeFragment(secondFragment, "secondFragment");
return true;
case R.id.menu_map:
changeFragment(thirdFragment, "thirdFragment");
return true;
}
return false;
}
});
public void changeFragment(Fragment fragment, String tagFragmentName) {
FragmentManager mFragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
Fragment currentFragment = mFragmentManager.getPrimaryNavigationFragment();
if (currentFragment != null) {
fragmentTransaction.detach(currentFragment);
}
Fragment fragmentTemp = mFragmentManager.findFragmentByTag(tagFragmentName);
if (fragmentTemp == null) {
fragmentTemp = fragment;
fragmentTransaction.add(R.id.content, fragmentTemp, tagFragmentName);
} else {
fragmentTransaction.attach(fragmentTemp);
}
fragmentTransaction.setPrimaryNavigationFragment(fragmentTemp);
fragmentTransaction.setReorderingAllowed(true);
fragmentTransaction.commitNowAllowingStateLoss();
}
我为 FragmentManager 写了一个 Kotlin 扩展函数 class
fun FragmentManager.switch(containerId: Int, newFrag: Fragment, tag: String) {
var current = findFragmentByTag(tag)
beginTransaction()
.apply {
//Hide the current fragment
primaryNavigationFragment?.let { hide(it) }
//Check if current fragment exists in fragmentManager
if (current == null) {
current = newFrag
add(containerId, current!!, tag)
} else {
show(current!!)
}
}
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
.setPrimaryNavigationFragment(current)
.setReorderingAllowed(true)
.commitNowAllowingStateLoss()
}
这可以由 supportFragmentManager.swtich(R.id.container,newFrag,newFrag.TAG)
从 onNavigationItemSelected
Thomas 的回答几乎帮助了我,但有一个问题,每当我第一次打开新片段时,它们会重叠,但一旦我按下菜单按钮再次打开它们就不会重叠。
于是我修改了他的代码,使用如下代码得到了解决方案:
private fun selectContentFragment(fragmentToSelect: Fragment) {
val fragmentTransaction = fragmentManager?.beginTransaction()
if (fragmentManager?.fragments?.contains(fragmentToSelect)!!) {
// Show the fragment that we want to be selected.
fragmentTransaction?.show(fragmentToSelect)
} else {
// The fragment to be selected does not (yet) exist in the fragment manager, add it.
fragmentTransaction?.add(R.id.container, fragmentToSelect)
}
// Iterate through all cached fragments.
for (cachedFragment in fragmentManager?.fragments!!) {
if (cachedFragment !== fragmentToSelect) {
// Hide the fragments that are not the one being selected.
// Uncomment following line and change the name of the fragment if your host isn't an activity and a fragment otherwise whole view will get hidden.
// if (!cachedFragment.toString().contains("HomeContainerFragment"))
fragmentTransaction?.hide(cachedFragment)
}
}
fragmentTransaction?.commit()
}
确保您不会每次都传递片段的新实例。
这行得通:
selectContentFragment(
when (item.itemId) {
R.id.home -> frag1
R.id.photoGallery -> frag2
else -> Home()
}
)
其中 frag1
和 frag2
是全局变量,定义为:
val frag1 = Home()
val frag2 = PhotoGallery()
这行不通:
selectContentFragment(
when (item.itemId) {
R.id.home -> Home()
R.id.photoGallery -> PhotoGallery()
else -> Home()
}
)
浪费了我好几个小时。希望对大家有帮助!
**这段代码对我很有帮助。就像优酷一样。 **
private Deque<Integer> fragmentIds = new ArrayDeque<>(3);
int itemId;
private HomeFragment homeFragment = new HomeFragment();
private FavouriteFragment favouriteFragment = new FavouriteFragment();
private NearmeFragment nearmeFragment = new NearmeFragment();
BottomNavigationView bottomNavigationView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
fragmentIds.push(R.id.action_home);
showTabWithoutAddingToBackStack(homeFragment);
bottomNavigationView = findViewById(R.id.bottom_navigation);
bottomNavigationView.setOnNavigationItemSelectedListener(onNavigationItemClicked);
}
private BottomNavigationView.OnNavigationItemSelectedListener onNavigationItemClicked = new BottomNavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
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.action_home:
return homeFragment;
case R.id.action_favorites:
return favouriteFragment;
case R.id.action_nearme:
return nearmeFragment;
}
return homeFragment;
}
private void showTabWithoutAddingToBackStack(Fragment fragment) {
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, fragment, fragment.getClass().getSimpleName()).commit();
}
@Override
public void onBackPressed() {
if(fragmentIds.getLast() != R.id.action_home){
fragmentIds.addLast(R.id.action_home);
}
fragmentIds.pop();
bottomNavigationView.getMenu().getItem(fragmentIds.size()-1).setChecked(true);
if (!fragmentIds.isEmpty()) {
showTabWithoutAddingToBackStack(getFragment(fragmentIds.peek()));
} else {
finish();
}
}
对于 Kotlin 用户可以帮助此代码:
首先创建一个FragmentManager扩展class
fun FragmentManager.replace(containerId: Int, fragment: Fragment, tag: String) {
var current = findFragmentByTag(tag)
beginTransaction()
.apply {
//Hide the current fragment
primaryNavigationFragment?.let { hide(it) }
//Check if current fragment exists in fragmentManager
if (current == null) {
current = fragment
add(containerId, current!!, tag)
} else {
show(current!!)
}
}
.setTransition(FragmentTransaction.TRANSIT_ENTER_MASK)
.setPrimaryNavigationFragment(current)
.setReorderingAllowed(true)
.commitNowAllowingStateLoss()
}
现在只需在您的
上调用它 onNavigationItemSelected
supportFragmentManager.replace(R.id.fragment_id,YourFragmentClass,yourFragment.TAG)
我有同样的问题,但我通过创建多个片段主机解决了它,然后我在 fragmentHost 中添加了片段。当底部导航 itemSelected 时,我只是使所需的主机片段可见,而其他主机片段主机可见性消失了。
这个方法可能有误,但对我来说很管用。 而且我们不必手动处理片段的状态,只需要处理 activity 的背压。 但是这个方法不会暂停片段。
而且我不知道如何处理片段的暂停和恢复所以请回复我。
也许这会对你有所帮助。
这是我的 fragmentHosts 主页 Activity:
<androidx.fragment.app.FragmentContainerView
android:id="@+id/homeFragmentHost"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@+id/bottom_NavBar"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:visibility="gone"/>
<androidx.fragment.app.FragmentContainerView
android:id="@+id/libraryFragmentHost"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@+id/bottom_NavBar"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:visibility="gone"/>
<androidx.fragment.app.FragmentContainerView
android:id="@+id/myStuffFragmentHost"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@+id/bottom_NavBar"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:visibility="gone"/>
<androidx.fragment.app.FragmentContainerView
android:id="@+id/moreFragmentHost"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@+id/bottom_NavBar"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:visibility="gone"/>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/bottom_NavBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:menu="@menu/app_bottom_nav_menu"
tools:ignore="BottomAppBar" />
首页Activity onCreate:
supportFragmentManager.beginTransaction().replace(R.id.homeFragmentHost,HomeFragment()).commitNow()
supportFragmentManager.beginTransaction().replace(R.id.libraryFragmentHost,LibraryFragment()).commitNow()
supportFragmentManager.beginTransaction().replace(R.id.myStuffFragmentHost,MyStuffFragment()).commitNow()
supportFragmentManager.beginTransaction().replace(R.id.moreFragmentHost,MoreFragment()).commitNow()
homeFragmentHost.visibility = View.VISIBLE
底部导航项目选定的侦听器
override fun onNavigationItemSelected(item: MenuItem): Boolean {
return when(item.itemId){
R.id.homeFragment -> loadFragmentHost(homeFragmentHost)
R.id.libraryFragment -> loadFragmentHost(libraryFragmentHost)
R.id.myStuffFragment -> loadFragmentHost(myStuffFragmentHost)
R.id.moreFragment -> loadFragmentHost(moreFragmentHost)
else -> false
}
loadFragmentHost 函数
private fun loadFragmentHost(view:FragmentContainerView): Boolean {
val list = arrayListOf(homeFragmentHost,libraryFragmentHost,myStuffFragmentHost,moreFragmentHost)
list.remove(view)
view.visibility = View.VISIBLE
list.forEach {
it.visibility = View.GONE
}
return true
}
public class MainActivity extends AppCompatActivity {
boolean doubleBackToExitPressedOnce = false;
final Fragment fragment1 = new HomeFragment();
final Fragment fragment2 = new DashboardFragment();
final Fragment fragment3 = new NotificationsFragment();
final FragmentManager fm = getSupportFragmentManager();
Fragment active = fragment1;
BottomNavigationView navigation;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
navigation = (BottomNavigationView) findViewById(R.id.navigation);
navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
setFragment(fragment1, "1", 0);
}
private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
= new BottomNavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.navigation_home:
setFragment(fragment1, "1", 0);
return true;
case R.id.navigation_dashboard:
setFragment(fragment2, "2", 1);
return true;
case R.id.navigation_notifications:
setFragment(fragment3, "3", 2);
return true;
}
return false;
}
};
public void setFragment(Fragment fragment, String tag, int position) {
if (fragment.isAdded()) {
fm.beginTransaction().hide(active).show(fragment).commit();
} else {
fm.beginTransaction().add(R.id.main_container, fragment, tag).commit();
}
navigation.getMenu().getItem(position).setChecked(true);
active = fragment;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main_menu, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_settings) {
startActivity(new Intent(MainActivity.this, SettingsActivity.class));
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onBackPressed() {
if (active == fragment1) {
if (doubleBackToExitPressedOnce) {
super.onBackPressed();
return;
}
this.doubleBackToExitPressedOnce = true;
Toast.makeText(this, "Please click BACK again to exit", Toast.LENGTH_SHORT).show();
} else {
setFragment(fragment1, "1", 0);
}
}
}
- 维护底部sheet片段
Reusable
- BackPress 维护
- 双击退出
public class MainActivity extends AppCompatActivity {
BottomNavigationView bottomNavigationView;
Toaster toaster;
private final Fragment androidFragment = new AndroidFragment();
private final Fragment settingsFragment = new SettingsFragment();
Fragment active;
String TAG = MainActivity.class.getSimpleName();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
toaster = new Toaster(this);
bottomNavigationView = findViewById(R.id.bottom_navigation);
renderFragment(androidFragment, "android");
active = androidFragment;
bottomNavigationView.setOnItemSelectedListener(
item -> {
Log.e(TAG, "onCreate: " + active );
if(item.getItemId() == R.id.action_android){
renderFragment(androidFragment, "android");
return true;
}
else if(item.getItemId() == R.id.action_settings){
renderFragment(settingsFragment, "settings");
return true;
}
return false;
}
);
}
private void renderFragment(Fragment fragment, String tag){
FragmentManager fragmentManager = getSupportFragmentManager();
if(fragment.isAdded()){
fragmentManager.beginTransaction().hide(active).show(fragment)
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN).commit();
}
else {
if(active != null){
getSupportFragmentManager().beginTransaction()
.add(R.id.fragment_container_view, fragment, tag)
.hide(active)
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN).commit();
}
else {
getSupportFragmentManager().beginTransaction()
.add(R.id.fragment_container_view, fragment, tag)
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN).commit();
}
}
active = fragment;
}
}
伙计们,这对我有用。