2017-04-07 38 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

我正在使用片段导致底部导航视图代码将被写入单一时间工具栏和导航代码将被写入一次。 –