在ViewPager中使用返回栈和返回按钮

8
我正在使用viewpager在不同的fragment之间进行滑动,希望返回按钮可以导航到先前查看的fragment,而不是结束activity。如果这是此问题的重复,请原谅,但我没有找到很有用的答案。显然需要覆盖onBackPressed方法,但我不知道如何获取并显示正确的fragment。我假设应该使用fragmentmanager的后退栈,但getSupportFragmentManager().getBackStackEntryCount()总是返回0。我需要手动使用FragmentTransaction.addToBackStack()将fragments添加到后退栈中吗?如果需要,我应该在适配器中的哪里添加它?
以下是我的activity代码:
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();
  }
}


}
5个回答

8
在新的设计支持库中,我使用了这个。
我有同样的问题,然后我按照以下步骤进行操作:
在主要的活动中,有3个片段在viewpager中,我创建了一个堆栈并推入和弹出数据。
//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<Integer> stackkk;到 private Stack<Integer> stackkk = new Stack<>();创建新对象每次都要执行。 - Ravikant Paudel

2
请在片段活动类中使用此代码。不要忘记添加 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);

}

1
我之前也遇到过类似的问题,这是我解决的方法。如果我理解你的问题,我认为你可以根据我的代码适应你的问题。我有一个带有6个片段的ViewPager,并希望跟踪页面历史记录并能够使用后退按钮向后导航。我创建了一个java.util.Stack<Integer>对象,将片段号添加到其中(除非您使用后退按钮,请参见下文),并覆盖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;
    }
};

0

我已经制作了自定义的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;
}

0

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

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


用户可以向任意方向导航,因此第二种解决方案不可行。我刚试着实现了第一种解决方案,通过添加一个 OnPageChangeListener 并在那里记录索引,但是行为不一致。有时候显示的页面不会改变,即使我可以从日志中看到下一个片段正在被实例化。 - Igd
此外,手动跟踪索引感觉像是一种相当“非Android”的解决方案,因为后退堆栈已经存在于此目的。 - Igd
2
嗯,我不确定为什么会出现这种不一致的情况,但需要注意的是ViewPager实际上会在内存中始终保留3个页面:当前页面、前一页和下一页。因此,如果您当前正在第2页(第1页、第2页和第3页已经被实例化),然后移动到第3页,那么第4页将被实例化,而第1页将被删除。 - Frank Cangialosi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接