【问题标题】:Using backstack and back button in viewpager在 viewpager 中使用 backstack 和 back 按钮
【发布时间】:2013-08-26 21:25:37
【问题描述】:

我正在使用 viewpager 在片段之间滑动,并希望后退按钮导航到先前查看的片段,而不是结束活动。抱歉,如果这是 this question 的副本,但我没有发现答案很有帮助。显然 onBackPressed 需要被覆盖,但我不知道如何获取和显示正确的片段。我假设我应该使用 fragmentmanager 的 backstack,但getSupportFragmentManager().getBackStackEntryCount() 总是返回 0。我是否需要使用 FragmentTransaction.addToBackStack() 手动将 Fragment 添加到 backstack?如果是这样,我会在我的适配器中的什么位置添加它?

这是我的活动代码,

public class PagerActivity extends FragmentActivity {

ArrayList<Sale> sales;
MyAdapter mAdapter;
ViewPager mPager;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    Intent it = getIntent();
    this.sales = (ArrayList<Sale>) it.getExtras().get("sales");
    int position = it.getExtras().getInt("position");

    ActionBar actionBar = getActionBar();
    actionBar.setDisplayHomeAsUpEnabled(true);

    setContentView(R.layout.fragment_pager);
    mAdapter = new MyAdapter(getSupportFragmentManager());
    mPager = (ViewPager) findViewById(R.id.pager);
    mPager.setAdapter(mAdapter);
    mPager.setCurrentItem(position);

}

public class MyAdapter extends FragmentPagerAdapter {
    public MyAdapter(FragmentManager fragmentManager) {
        super(fragmentManager);
    }

    @Override
    public int getCount() {
        return sales.size();
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        super.destroyItem(container, position, object);
    }

    @Override
    public Fragment getItem(int position) {
        SalesThumbFragment frag = new SalesThumbFragment();
        return frag.newInstance(sales.get(position));
    }
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
    case android.R.id.home:
        finish();
        return true;
    }
    return super.onOptionsItemSelected(item);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.sales_controller, menu);
    return true;
}

@Override
public void onBackPressed() {
  if(getSupportFragmentManager().getBackStackEntryCount() != 0) {
    getSupportFragmentManager().popBackStack();
  } else {

    super.onBackPressed();
  }
}


}

【问题讨论】:

    标签: android android-fragments android-viewpager back-stack


    【解决方案1】:

    在新的设计支持库中,我使用这个
    我有同样的问题,我按照这个步骤操作

    在 viewpager 中有 3 个片段的主要活动中,我创建了堆栈 并推送和弹出数据。

    //private Stack<Integer> stackkk;  ==> As i get edit suggestion 
    private Stack<Integer> stackkk = new Stack<>(); // Edited 
    private ViewPager mPager;
    private int tabPosition = 0;
    
    
    
        mTabLayout.setupWithViewPager(mPager);
        mPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(mTabLayout));
        mTabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
            @Override
            public void onTabSelected(TabLayout.Tab tab) {
                tabPosition = tab.getPosition();
                mPager.setCurrentItem(tab.getPosition());
    
                if (stackkk.empty())
                    stackkk.push(0);
    
                if (stackkk.contains(tabPosition)) {
                    stackkk.remove(stackkk.indexOf(tabPosition));
                    stackkk.push(tabPosition);
                } else {
                    stackkk.push(tabPosition);
                }
            }
    
            @Override
            public void onTabUnselected(TabLayout.Tab tab) {
                tabPositionUnselected = tab.getPosition();
            }
    
            @Override
            public void onTabReselected(TabLayout.Tab tab) {
            }
        });
    }
    

    并在onBackPressed活动中,

    @Override
    public void onBackPressed() {
        if (stackkk.size() > 1) {
            stackkk.pop();
            mPager.setCurrentItem(stackkk.lastElement());
        } else {
        }
    }
    

    【讨论】:

    • 感谢您的编辑建议,因为我已将代码形式更改为 private Stack stackkk;到私有 Stack stackkk = new Stack();每次都创建新对象。
    【解决方案2】:

    在 Fragment Activity 类中使​​用此代码。别忘了加上return true;

    public boolean onKeyDown(int keyCode, KeyEvent event) {
    
        // TODO Auto-generated method stub
        if ((keyCode == KeyEvent.KEYCODE_BACK)) {
    
                mViewPager.setCurrentItem(viewPageSelected - 1);
                return true;
            }
    
        return super.onKeyDown(keyCode, event);
    
    }
    

    【讨论】:

      【解决方案3】:

      我遇到了类似的问题,我就是这样解决的。如果我了解您的问题,我认为您可以根据您的问题调整代码。我有一个包含 6 个片段的 ViewPager,并且想要跟踪页面历史记录并能够使用后退按钮在历史记录中向后导航。我创建了一个java.util.Stack&lt;Integer&gt; 对象,向其中添加片段编号(使用后退按钮时除外,见下文),并在我的历史堆栈时覆盖onBackPressed() 以使其弹出最后查看的片段而不是使用后退堆栈不为空。

      当你按下后退按钮时,你要避免将元素压入堆栈,否则如果你继续使用后退按钮,你会卡在两个片段之间,而不是最终退出。

      我的代码:

      MyAdapter mAdapter;
      ViewPager mPager;
      Stack<Integer> pageHistory;
      int currentPage;
      boolean saveToHistory;
      
      @Override
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.activity_main);
      
          mAdapter = new MyAdapter(getSupportFragmentManager());
          mPager = (ViewPager)findViewById(R.id.container);
          mPager.setAdapter(mAdapter);
          mPager.setOffscreenPageLimit(5);
      
          pageHistory = new Stack<Integer>();
          mPager.setOnPageChangeListener(new OnPageChangeListener() {
      
              @Override
              public void onPageSelected(int arg0) {
                  if(saveToHistory)
                      pageHistory.push(Integer.valueOf(currentPage));
              }
      
              @Override
              public void onPageScrolled(int arg0, float arg1, int arg2) {
              }
      
              @Override
              public void onPageScrollStateChanged(int arg0) {
              }
          });
          saveToHistory = true;
      }
      
      @Override
      public void onBackPressed() {
          if(pageHistory.empty())
              super.onBackPressed();
          else {
              saveToHistory = false;
              mPager.setCurrentItem(pageHistory.pop().intValue());
              saveToHistory = true;
          }
      };
      

      【讨论】:

        【解决方案4】:

        如果您在每次用户导航到新片段后使用mPager.getCurrentItem() 使用字段来跟踪上一页的索引,那么在onBackPressed() 方法中,您应该可以调用mPager.setCurrentItem(previousPage)

        或者,如果用户只能按顺序翻页,那么你根本不需要一个字段,你可以这样做mPager.setCurrentItem(mPager.getCurrentItem()-1)

        【讨论】:

        • 用户可以在任一方向导航,因此第二个解决方案将不起作用。我刚刚尝试通过添加OnPageChangeListener 并在那里记录索引来实现第一个解决方案,但行为不一致。有时显示的页面不会改变,即使我可以从日志中看到下一个片段正在被实例化。
        • 此外,手动跟踪索引感觉像是一个非常“非安卓”的解决方案,因为为此目的已经存在后台堆栈
        • 嗯,我不知道为什么会出现这种不一致,但重要的是要注意 ViewPager 实际上始终在内存中保留 3 个页面:当前页面、前一页面和下一页。因此,如果您当前在第 2 页(当前已实例化第 1、2 和 3 页)然后移动到第 3 页,例如,第 4 页将被实例化,第 1 页将被删除。
        【解决方案5】:

        我已经制作了自定义 ViewPager 并在其中实现了堆栈功能。

        public class CustomViewPager extends ViewPager {
        
        private Stack<Integer> stack = new Stack<>();
        
        @Override
        public void setCurrentItem(int item, boolean smoothScroll) {
            stack.push(getCurrentItem());
            super.setCurrentItem(item, smoothScroll);
        }
        
        public int popFromBackStack(boolean smoothScroll) {
            if (stack.size()>0) {
                super.setCurrentItem(stack.pop(), smoothScroll);
                return getCurrentItem();
            } else return -1;
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-09-24
          • 2020-06-21
          • 1970-01-01
          • 2015-05-28
          • 1970-01-01
          • 2012-06-11
          相关资源
          最近更新 更多