以下は、選択された下部ナビゲーションビューアイテムのコードです
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;
}
});
今私の問題は、フラグメントが再作成されるたびに、addToBackStack(null)を追加しようとするたびにフラグメントを再作成することを望まないことですが、この場合、戻るボタンを押すと、不要なスタックからフラグメントがポップされ続けます。
フラグメントを再作成せずに選択された下部ナビゲーションバーにフラグメントを表示する方法はありますか
サポートライブラリ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();
replace
を使用するときは注意してください。既にメモリに存在するフラグメントを提供する場合でも、replace
はフラグメントのライフサイクルを再開します。再起動を回避するために、トランザクションオブジェクトのメソッドにはadd
、show
、およびhide
が含まれています。これらを使用すると、再起動せずに正しいフラグメントを表示できます。
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()
}
私は同じ問題に直面し、最後に解決策を見つけました。このコードを試すことができます。それは私のために働いています。
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();
}
});
}
}
これを試して :
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;
}
});
container
の現在のフラグメントが取得されます。このフラグメントを再度クリックすると、フラグメントは再追加されません。
これは私にとってはうまくいくように思えました。アタッチとデタッチの代わりに、フラグメントの状態を維持するために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();
}
そして、これは私がそれを使用する方法です
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());
}
setOnNavigationItemReselectedListenerは、そのためのより良いソリューションです
次のようにsetOnNavigationItemReselectedListenerを使用します。
private BottomNavigationView.OnNavigationItemReselectedListener onNavigationItemReselectedListener
= new BottomNavigationView.OnNavigationItemReselectedListener() {
@Override
public void onNavigationItemReselected(@NonNull MenuItem item) {
Toast.makeText(MainActivity.this, "Reselected", Toast.LENGTH_SHORT).show();
}
};
そして、それを使用して呼び出します:
navigation.setOnNavigationItemReselectedListener(onNavigationItemReselectedListener);
すべてのナビゲーションフラグメントを委任するViewPager
を追加することで、この問題を解決しました。そのアダプター(FragmentPagerAdapter
)は、ユーザーがBotoomNavigationView
をナビゲートするときにフラグメントインスタンスを再作成しません。
これを実現するには、5つの簡単な手順を完了する必要があります。
ViewPager
をレイアウトに追加します。アダプタを実装します。
class YourNavigationViewPagerAdapter(fm: FragmentManager,
private val param1: Int,
private val param2: Int)
: FragmentPagerAdapter(fm) {
override fun getItem(p0: Int) = when(p0) {
0 -> NavigationFragment1.newInstance(param1, param2)
1 -> NavigationFragment2.newInstance(param1, param2)
2 -> NavigationFragment3.newInstance(param1, param2)
else -> null
}
override fun getCount() = 3
}
新しいアダプターを設定することを忘れないでください:
yourViewPager.adapter = YourNavigationViewPagerAdapter(supportFragmentManager, param1, param2)
次のようにOnNavigationItemSelectedListener
をBottomNavigationView
に設定します。
yourBottomNavigationView.setOnNavigationItemSelectedListener {
when(it.itemId) {
R.id.yourFirstFragmentMenuItem -> {
yourViewPager.currentItem = 0
true
}
R.id.yourSecondFragmentMenuItem -> {
yourViewPager.currentItem = 1
true
}
R.id.yourThirdFragmentMenuItem -> {
yourViewPager.currentItem = 2
true
}
else -> false
}
}
次のようにOnPageChangeListener
をViewPager
に設定します。
yourViewPager.addOnPageChangeListener(object :
ViewPager.OnPageChangeListener {
override fun onPageScrollStateChanged(p0: Int) {
}
override fun onPageScrolled(p0: Int, p1: Float, p2: Int) {
}
override fun onPageSelected(p0: Int) {
yourBottomNavigationView.menu.getItem(p0).isChecked = true
}
})
楽しい :)
同じために、Kotlinで拡張機能を作成しました。
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()
}
適切なナビゲーションに関連するテストケースがいくつかあります。すべてのテストケースをチェックしてコードを貼り付けています。
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
switch (item.getItemId()) {
case R.id.dashboard:
Fragment fragment;
fragment = fragmentManager.findFragmentByTag(DashboardFragment.TAG);
if (fragment == null) {
fragment = new DashboardFragment();
fragmentTransaction.add(R.id.frame, fragment, DashboardFragment.TAG);
} else {
fragmentTransaction.detach(fragmentManager.getPrimaryNavigationFragment());
fragmentTransaction.attach(fragment);
}
fragmentTransaction.setPrimaryNavigationFragment(fragment);
fragmentTransaction.commitNow();
return true;
case R.id.expenses:
fragment = fragmentManager.findFragmentByTag(ExpenseFragment.TAG);
if (fragment == null) {
fragment = new ExpenseFragment();
fragmentTransaction.add(R.id.frame, fragment, ExpenseFragment.TAG);
} else {
fragmentTransaction.detach(fragmentManager.getPrimaryNavigationFragment());
fragmentTransaction.attach(fragment);
}
fragmentTransaction.setPrimaryNavigationFragment(fragment);
fragmentTransaction.commitNow();
return true;
case R.id.vehicle_parts:
Bundle bundle = new Bundle();
bundle.putInt("odometer", vehicle.getOdometer());
bundle.putString("vehicle_id", vehicle.get_id());
fragment = fragmentManager.findFragmentByTag(PartsFragment.TAG);
if (fragment == null) {
fragment = new PartsFragment();
fragment.setArguments(bundle);
fragmentTransaction.add(R.id.frame, fragment, PartsFragment.TAG);
} else {
fragmentTransaction.detach(fragmentManager.getPrimaryNavigationFragment());
fragmentTransaction.attach(fragment);
}
fragmentTransaction.setPrimaryNavigationFragment(fragment);
fragmentTransaction.commitNow();
return true;
case R.id.blog:
fragment = fragmentManager.findFragmentByTag(BlogFragment.TAG);
if (fragment == null) {
fragment = new BlogFragment();
fragmentTransaction.add(R.id.frame, fragment, BlogFragment.TAG);
} else {
fragmentTransaction.detach(fragmentManager.getPrimaryNavigationFragment());
fragmentTransaction.attach(fragment);
}
fragmentTransaction.setPrimaryNavigationFragment(fragment);
fragmentTransaction.commitNow();
return true;
}
return false;
@Vivenの回答を改善し、Kotlinで作成しました。私のバージョンでは、フラグメントを初めてインスタンス化し、非表示/表示します。私はKotlinに新しいので、何か改善できるか教えてください。
マップをタグ付けするためにidを保持する必要があります。
private val fragmentTags = hashMapOf(
R.id.action_home to "home_fragment",
R.id.action_profile to "profile_fragment"
)
リスナーコード:
bottomNavigation.run {
setOnNavigationItemSelectedListener { menuItem ->
supportFragmentManager.beginTransaction()
.let { transaction ->
// hide current fragment
supportFragmentManager.primaryNavigationFragment?.let {
// if selected fragment's tag is same, do nothing.
if (it.tag == fragmentTags[menuItem.itemId]) {
return@setOnNavigationItemSelectedListener true
}
transaction.hide(it)
}
var fragment = supportFragmentManager.findFragmentByTag(fragmentTags[menuItem.itemId])
if (fragment == null) {
// instantiate fragment for the first time
fragment = when(menuItem.itemId) {
R.id.action_home -> HomeFragment()
R.id.action_profile -> ProfileFragment()
else -> null
}?.also {
// and add it
transaction.add(R.id.frame, it, fragmentTags[menuItem.itemId])
}
} else {
// if it's found show it
transaction.show(fragment)
}
transaction
.setPrimaryNavigationFragment(fragment)
.setReorderingAllowed(true)
}.commitNowAllowingStateLoss()
return@setOnNavigationItemSelectedListener true
}
//bottomNavigation things
itemIconTintList = null
selectedItemId = R.id.action_home
}