2017-04-07 73 views
0

你好我正在使用BottomNavigationViewBottomNavigationView中的每一項都會打開一個片段,它將存儲在後備堆棧中,但是如果多次選擇了一個後備堆棧,將會存儲該片段的最新實例。我的意思是當按下按鈕片段時只會打開一次。Android限制片段只有一次返回堆棧

比如,有3 fragments..A,B,C

片段模式:ABCBACAC

返回按輸出應該是:CAB-出口

但我會得到這個圖案 - CACABCBA退出

這裏是我using-代碼

@Override 
public boolean onNavigationItemSelected(@NonNull MenuItem item) { 
    switch (item.getItemId()){ 
     case R.id.nav_home: 
      mFragment = getSupportFragmentManager().findFragmentByTag("Fragment_Home"); 
      if(!(mFragment!=null && mFragment.isVisible())){ 
       mFragmentManager.popBackStackImmediate("Fragment_Home", FragmentManager.POP_BACK_STACK_INCLUSIVE); 
       mFragmentTransaction = mFragmentManager.beginTransaction(); 
       mFragmentTransaction.replace(R.id.container, new HomeFragment(), "Fragment_Home").addToBackStack("Fragment_Home").commit(); 
      } 
      return true; 
     case R.id.nav_account: 
      mFragment = getSupportFragmentManager().findFragmentByTag("Fragment_Account"); 
      if(!(mFragment != null && mFragment.isVisible())){ 
       mFragmentManager.popBackStackImmediate("Fragment_Account", FragmentManager.POP_BACK_STACK_INCLUSIVE); 
       mFragmentTransaction = mFragmentManager.beginTransaction(); 
       mFragmentTransaction.replace(R.id.container, new AccountFragment(), "Fragment_Account").addToBackStack("Fragment_Account").commit(); 
      } 
      return true; 
     case R.id.nav_category: 
      mFragment = getSupportFragmentManager().findFragmentByTag("Fragment_Category"); 
      if(!(mFragment != null && mFragment.isVisible())){ 
       mFragmentManager.popBackStackImmediate("Fragment_Category", FragmentManager.POP_BACK_STACK_INCLUSIVE); 
       mFragmentTransaction = mFragmentManager.beginTransaction(); 
       mFragmentTransaction.replace(R.id.container, new CategoryFragment(), "Fragment_Category").addToBackStack("Fragment_Category").commit(); 
      } 
      return true; 
    } 
    return false; 
} 

@Override 
public void onBackPressed() { 
    if (mDrawerLayout.isDrawerOpen(GravityCompat.START)) { 
     mDrawerLayout.closeDrawer(GravityCompat.START);   
    } 
    else if (getSupportFragmentManager().getBackStackEntryCount() > 0) { 
     getSupportFragmentManager().popBackStack(); 
    } 
    else if (doubleBackToExitPressedOnce) { 
     finishAffinity(); 
    } 
    else { 
     this.doubleBackToExitPressedOnce = true; 
     Toast.makeText(this, "Please BACK again to exit", Toast.LENGTH_SHORT).show(); 
     new Handler().postDelayed(new Runnable() { 
      @Override 
      public void run() { 
       doubleBackToExitPressedOnce = false; 
      } 
     }, 2000); 
    } 
} 

給我一些想法我的代碼有什麼問題。任何幫助,將不勝感激。

回答

1

對於這個問題,我建議您使用Viewpager而不是Fragment back-stack。首先,我會告訴你爲什麼不應該使用Fragment backstack。 我想你的代碼,只要你的活動創建。你會立即轉移到你的First Fragment。例如:A-B-C-C-C-C-C或A-B-C-A-B-C-A-B-B。這會像你所說的那樣去除後臺碎片,每當你再次單擊一個碎片時,你將創建一個新碎片。 以下是使用Viewpager的其他方法,使UX更好。 首先,我定製我自己FragmentStatePagerAdapter有更好的表現

public abstract class SmartFragmentStatePagerAdapter extends FragmentStatePagerAdapter { 
    // Sparse array to keep track of registered fragments in memory 
    private SparseArray<Fragment> registeredFragments = new SparseArray<Fragment>(); 

    public SmartFragmentStatePagerAdapter(FragmentManager fragmentManager) { 
     super(fragmentManager); 
    } 

    // Register the fragment when the item is instantiated 
    @Override 
    public Object instantiateItem(ViewGroup container, int position) { 
     Fragment fragment = (Fragment) super.instantiateItem(container, position); 
     registeredFragments.put(position, fragment); 
     return fragment; 
    } 

    // Unregister when the item is inactive 
    @Override 
    public void destroyItem(ViewGroup container, int position, Object object) { 
     registeredFragments.remove(position); 
     super.destroyItem(container, position, object); 
    } 

    // Returns the fragment for the position (if instantiated) 
    public Fragment getRegisteredFragment(int position) { 
     return registeredFragments.get(position); 
    } 
} 

讓創建CustomViewPager

public class CustomViewPager extends ViewPager { 

    public CustomViewPager(Context context) { 
     super(context); 
     setMyScroller(); 
    } 

    public CustomViewPager(Context context, AttributeSet attrs) { 
     super(context, attrs); 
     setMyScroller(); 
    } 

    @Override 
    public boolean onInterceptTouchEvent(MotionEvent event) { 
     // Never allow swiping to switch between pages 
     return false; 
    } 

    @Override 
    public boolean onTouchEvent(MotionEvent event) { 
     // Never allow swiping to switch between pages 
     return false; 
    } 

    //down one is added for smooth scrolling 

    private void setMyScroller() { 
     try { 
      Class<?> viewpager = ViewPager.class; 
      Field scroller = viewpager.getDeclaredField("mScroller"); 
      scroller.setAccessible(true); 
      scroller.set(this, new MyScroller(getContext())); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 

    public class MyScroller extends Scroller { 
     public MyScroller(Context context) { 
      super(context, new DecelerateInterpolator()); 
     } 

     @Override 
     public void startScroll(int startX, int startY, int dx, int dy, int duration) { 
      super.startScroll(startX, startY, dx, dy, 350 /*1 secs*/); 
     } 
    } 
} 

把它放在你的XML文件是這樣的:

<YOUR_PACKAGE_NAME.CustomViewPager 
     android:id="@+id/viewPager" 
     android:layout_width="match_parent" 
     android:layout_height="match_parent" 
     /> 

這是ViewPager的適配器:

public class ViewPagerAdapter extends SmartFragmentStatePagerAdapter { 
    private static int NUM_ITEMS = 3; 
    private BaseFragment mFragment1, mFragment2, mFragment3; 

    public ViewPagerAdapter(FragmentManager fragmentManager) { 
     super(fragmentManager); 

     mFragment1= Fragment1.newInstance(0, FRAGMENT_TAG_1); 
     mFragment2= Fragment2.newInstance(1, FRAGMENT_TAG_2); 
     mFragment3= Fragment3.newInstance(2, FRAGMENT_TAG_3); 
    } 


    @Override 
    public Fragment getItem(int position) { 
     switch (position) { 
      case 0: 
       return mFragment1; 
      case 1: 
       return mFragment2; 
      case 2: 
       return mFragment3; 
      default: 
       return null; 
     } 
    } 

    @Override 
    public int getCount() { 
     return NUM_ITEMS; 
    } 

    @Override 
    public int getItemPosition(Object object) { 
      return POSITION_NONE; 
    } 

    @Override 
    public Parcelable saveState() { 
     return null; 
    } 

} 

在你的活動,讓初始化它在onCreateView()

 mViewPager = (CustomViewPager) findViewById(R.id.viewPager); 
     mViewPagerAdapter = new ViewPagerAdapter(mFragmentManager); 
     mViewPager.setAdapter(mViewPagerAdapter); 
     mFrameLayout.setVisibility(View.GONE); 
     mViewPager.setVisibility(View.VISIBLE); 
     mViewPager.setSaveEnabled(true); 

當您點擊一個標籤,你只需要使用

mViewPager.setCurrentItem(NUMBER_OF_TIME); 
+0

主要問題的詳細信息是,我必須使用底部導航視圖也做同樣的事情與我的導航視圖。所以我必須解決這個問題。但無論如何感謝您的幫助 –

1

什麼,你應該做的是,宣佈活動,乙& C作爲「singleTop」

如果活動的一個實例,在當前任務的頂部已經存在系統通過調用onNewIntent()方法將意圖路由到該實例,而不是創建活動的新實例。該活動可以多次實例化,每個實例可以屬於不同的任務,並且一個任務可以具有多個實例(但只有當後棧的頂部的活動不是活動的現有實例時)。 例如,假設任務的後退堆棧由根活動A和頂部的活動B,C和D組成(堆棧是A-B-C-D; D在最前面)。意圖到達類型D的活動。如果D具有默認的「標準」啓動模式,則啓動該類的新實例,堆棧變爲A-B-C-D-D。但是,如果D的啓動模式是「singleTop」,則D的現有實例通過onNewIntent()接收意圖,因爲它位於堆棧的頂部 - 堆棧仍然是A-B-C-D。但是,如果意圖到達類型B的活動,則即使其啓動模式爲「singleTop」,也會將新的B實例添加到堆棧中。

注意:創建活動的新實例時,用戶可以按Back按鈕返回上一個活動。但是當一個活動的現有實例處理新的意圖時,用戶不能按按回退按鈕返回到 新的意圖到達onNewIntent()之前的活動狀態。

You should read the documentation here有關該主題的

+0

我正在使用片段導致底部導航視圖代碼將被寫入單一時間工具欄和導航代碼將被寫入一次。 –