将 backstack 与 ViewPager 一起使用

Posted

技术标签:

【中文标题】将 backstack 与 ViewPager 一起使用【英文标题】:Use backstack with ViewPager 【发布时间】:2012-09-24 15:24:45 【问题描述】:

我正在使用 ViewPager 在我的 android 应用中实现滑动。但是,我希望在用户使用后退按钮而不是结束活动时显示上一个片段。有没有办法做到这一点? 谢谢 塞巴斯蒂安

【问题讨论】:

【参考方案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;
    
;

【讨论】:

代码中currentPage 的值永远不会被设置。我通过使用一个名为lastPage 的变量来解决这个问题,并在推入堆栈后将其设置为onPageSelected 的参数。 arg0 是被导航到的页面,因此我们需要使用该变量来跟踪“上一页”。即使saveToHistory 为假,lastPage 也应更新。【参考方案2】:

在 Fragment Activity 中覆盖以下方法应该可以解决您的问题。

@Override
public void onBackPressed() 
    if (mViewPager.getCurrentItem() == 0) 
        // If the user is currently looking at the first step, allow the system to handle the
        // Back button. This calls finish() on this activity and pops the back stack.
        super.onBackPressed();
     else 
        // Otherwise, select the previous step.
        mViewPager.setCurrentItem(mViewPager.getCurrentItem() - 1);
    

【讨论】:

【参考方案3】:

覆盖 Activity 的功能:

public class Activity extends Activity

    @Override
    public void onBackPressed()
    
        // do stuff
        myFragment.onBackPressed();
    


public class Fragment extends Fragment


    public void onBackPressed()
    
        // do stuff
    

【讨论】:

【参考方案4】:

如果您使用的是 Jetpack Navigation 组件,那么您很可能只有一个 Activity 并试图管理 Fragment 中的 backstack。 在这种情况下,OnBackPressedDispatcher 就派上用场了。

【讨论】:

【参考方案5】:

我有同样的问题,我按照这个步骤操作(编辑了我的答案---当然对我有用,试试看

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

private Stack<Integer> stackkk;
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());

// here i have add the data into the stack in each tab click, as at first it will always be null so i add 0 position

            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活动中,

//OnbackPress i have first taken out the last one as it already and
//selected by poping it out then only set to the pager.
@Override
public void onBackPressed() 
    if (stackkk.size() > 1) 
        stackkk.pop();
        mPager.setCurrentItem(stackkk.lastElement());
     else 
    

希望这对我有帮助或给我留言。

【讨论】:

虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接的答案可能会失效。 @JaiprakashSoni 感谢您的建议。我已经编辑了我的答案。希望这可以帮助其他人【参考方案6】:

参考@Piero Nicolli 代码与 kotlin

这个 anwser 将与 instagram 导航一样工作 一旦你访问过同一个标签,你就不会再访问它了

  val pageHistory = Stack<Int>()
  var saveToHistory = false
  var viewPager: ViewPager? = null

如果您在 Fragment 中使用 viewPager,则在 Oncreate 或 OncreateView 内

viewPager?.adapter = viewPagerAdapter

 pageHistory.push(0);
        viewPager?.addOnPageChangeListener(object : ViewPager.OnPageChangeListener 
            override fun onPageScrolled(
                position: Int,
                positionOffset: Float,
                positionOffsetPixels: Int,
            ) 

            

            override fun onPageSelected(position: Int) 
                if (saveToHistory) 
                    if (pageHistory.contains(position)) 
                        pageHistory.remove(position)
                        pageHistory.push(position);
                     else 
                        pageHistory.push(position);
                    
                
            

            override fun onPageScrollStateChanged(state: Int) 
            
        )
        saveToHistory = true;
        requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner) 
            // Handle the back button event
            Log.i(TAG, "pageHistory size $pageHistory.size")
            if (pageHistory.size > 1) 

                saveToHistory = false;
                pageHistory.pop()
                viewPager?.currentItem = pageHistory.peek()
                saveToHistory = true;

             else 
                Log.i(TAG, "pageHistory inside 0 size $pageHistory.size")

                if(pageHistory.size ==1)
                    pageHistory.pop()
                
                if (viewPager?.currentItem == 0)
                    requireActivity().finish()
                else
                    viewPager?.currentItem = 0
                
            

        

当我使用 Fragment 时,后退按钮有回调 onBackPressedDispatcher。 如果您在 Activity 中使用 viewpager,则将代码从 onBackPressedDispatcher() 复制到 onBackPressed()

【讨论】:

以上是关于将 backstack 与 ViewPager 一起使用的主要内容,如果未能解决你的问题,请参考以下文章

当 ViewPager 中的 Fragment 从 BackStack 保留时 WebView 重新加载

具有多个 backstack 的片段

如何将 android 导航 backstack 弹出到某个片段?

将用户操作发送到 backstack 中的活动

在 Fragment 中管理 BackStack 的最佳方法是啥 [重复]

当我将 viewpager 与 Indicator Android 一起使用时,将背景状态栏更改为背景 viewpager?