【问题标题】:Sliding between fragments在片段之间滑动
【发布时间】:2015-09-24 16:48:00
【问题描述】:

我正在开发一个应用程序,目前我正在尝试将ScreenSlide 添加到它。我设法使用tutorial 做到了这一点,但x 页面之间的通常滑动并不是我想要的。

使用下面提供的代码,我可以在 5 页之间滑动,但页面对齐成一条直线,您不能从第一页直接转到第 5 页,反之亦然。 在我的应用程序中,我有 4 页。当我向左滑动时,我在前两页之间切换,当我向右滑动时,我在最后两页之间切换。在下图中,您可以看到我当前的代码如何切换页面及其下方 - 我的目标。

    public class MainActivity extends FragmentActivity {
    private static final int NUM_PAGES = 5;


    private ViewPager mPager;
    private ScreenSlidePageFragment[] pages = new ScreenSlidePageFragment[NUM_PAGES];


    private PagerAdapter mPagerAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_screen_slide);

        mPager = (ViewPager) findViewById(R.id.pager);
        mPagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager());
        mPager.setAdapter(mPagerAdapter);

    }

    @Override
    public void onBackPressed() {
        if (mPager.getCurrentItem() == 0) {
            super.onBackPressed();
        } else {
            mPager.setCurrentItem(mPager.getCurrentItem() - 1);
        } 
    }

    private class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter {
        public ScreenSlidePagerAdapter(FragmentManager fm) {
            super(fm);
        }



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

        @Override
        public Fragment getItem(int position) {
            boolean moveRight = mPager.getCurrentItem() < position;
            boolean moveLeft = mPager.getCurrentItem() > position;
            switch(position){
                case 5: 
                    if(moveRight){

                        return geLog.w("i"
                            + "Info", Integer.toString(position));
                       //return getPageByPosition(2);
                    if(moveLeft)
                        return getPageByPosition(2);


            }
            return new ScreenSlidePageFragment();
        }

        private Fragment getPageByPosition(int position){
            int index = position - 1;
            if(index < 0 || index > NUM_PAGES-1)
                throw new InvalidParameterException("requested position is invalid");

            if(pages[index] == null)
                pages[index] = new ScreenSlidePageFragment();
            return pages[index]; 
        }

    }


}

[更新]

我已经编写了一个代码,可以让我在 6 个不同的页面之间无限向右滑动。左侧是有限的——我只能滑动到第一页(所以如果我在向右循环 3 次后在第一页,我只能向后循环 3 个循环)。我想我非常接近找到解决方案。有什么想法吗?

MainActivity.java

    public class MainActivity extends FragmentActivity  {

private static final int NUM_PAGES = 6;
private ViewPager pager;
private PagerAdapter pagerAdapter;
private List<ScreenSlidePageFragment> slideList;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    slideList = new ArrayList<ScreenSlidePageFragment>();
    for (int i = 0; i<NUM_PAGES; i++){
        ScreenSlidePageFragment slide = new ScreenSlidePageFragment();
        slide.setIndex(i+1);
        slideList.add(slide);
    }

    pager = (ViewPager) findViewById(R.id.pager);
    pagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager());
    pager.setAdapter(pagerAdapter);
}

private class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter {

    public ScreenSlidePagerAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public Fragment getItem(int position) {
        int _pos = position % NUM_PAGES;
        return slideList.get(_pos);
    }

    @Override
    public int getCount() {
        return Integer.MAX_VALUE;
    }
}
}

ScreenSlidePageFragment.java

  public class ScreenSlidePageFragment extends Fragment {


        private int index;

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            ViewGroup root = (ViewGroup)inflater.inflate(R.layout.slide, container, false);
            TextView tw = (TextView) root.findViewById(R.id.textView);
            tw.setText(Integer.toString(index));
            return root;
        }

        public void setIndex(int index){
            this.index = index;
        }
        }

【问题讨论】:

  • 就页面持久性和用户体验而言,这是一个令人困惑的流程,我强烈建议您重新考虑您的导航设计。话虽如此,您可能需要自己进行动画和手势识别,而不是使用寻呼机适配器。否则,您将需要在每次页面更改后修改寻呼机适配器。 developer.android.com/reference/android/support/v4/app/…
  • 我给你 +1 的绘图 :-)
  • 覆盖每个片段中的onBackPressed();像这样的东西? onBackPressed() { getViewPager().setSelectedItem(0); }
  • 这不是您要找的吗? github.com/antonyt/InfiniteViewPager

标签: java android android-fragments android-fragmentactivity


【解决方案1】:

一种可能的解决方法是不使用 viewpager,而是创建您自己的自定义 Slider,我最终选择了这个解决方案,因为 ViewPager 非常不灵活,例如,如果您尝试做类似 Facebook Page 应用程序之类的事情。 缺点:你必须管理所有的接触和生命周期。

另一个更简单的解决方案基本上是使用以下 API,如果我正确理解了这个问题就足够了。 ViewPager.setCurrentItem

【讨论】:

    【解决方案2】:

    这就是我会做的。

    由于您的屏幕数量有限,我将创建一个数组来保存您在相应索引下创建的 ScreenSlidePageFragment 的每个实例。因此,您可以使用“位置”从该数组中获取一个实例。这将允许您利用 getItem 函数来执行类似的操作

    ...
    private ScreenSlidePageFragment[] pages = new ScreenSlidePageFragment[NUM_PAGES];
    ...
    
    @Override
    public Fragment getItem(int position) {
        boolean moveRight = mPager.getCurrentItem() < position;
        switch(position){
            case 1: 
                if(moveRight)
                    return getPageByPosition(3);
                return getPageByPosition(2);
            case 2: 
                if(moveRight)
                    //case when you are in a position 3 and swipe right - return first screen
                    return getPageByPosition(3);
                //if you're swiping left from position 1, return the next screen
                return getPageByPosition(1);
            case 3:
            //write out the rest of your logic 
            ...
        }
    }
    
    private Fragment getPageByPosition(int position){
        int index = position - 1;
        if(index < 0 || index > NUM_PAGES-1)
            throw new InvalidParameterException("requested position is invalid")
    
        if(pages[index] == null)
            pages[index] = new ScreenSlidePageFragment();
        return pages[index]; 
    }
    

    注意:代码未经测试

    基本上,您需要根据您当前的位置和请求的位置编写逻辑以返回片段的现有实例。

    【讨论】:

    • 我已经实现了你的代码,但是没有用。我简化了这个过程,所以我得到的问题更少,并且测试了如果我在第 5 次向右滑动是否可以到达第一页 - 没有成功。我已经更新了代码
    • 你调试了吗?当position5 时返回哪个片段?
    • 我还想知道您如何分辨哪个是哪个,因为您没有将任何内容传递给片段实例。如果有一些 UI 可以看起来不同,您可能还需要检查您的代码以确保正确保存/恢复片段状态,因为片段应该在进出视图时执行 onPauseonResume /跨度>
    • 我添加了 Log.w,每次我在指定页面上向右滑动手指时都会给我一条消息(查看更新的代码)。当我使用案例 4 时,它给了我一个 Log,但它不适用于案例 5。虽然显示了日志,但它并没有将我转移到第一页。到目前为止,我不需要查看片段上的内容 - 我只查看过渡本身。
    • 看看这里,我觉得会有帮助stackoverflow.com/questions/12141346/…
    【解决方案3】:

    你可以试试ViewPager.setCurrentItem

    如果你想导航到页面

    viewPager.setCurrentItem(PAGE_POS);
    

    如果你想导航到页面而不平滑滚动

    viewPager.setCurrentItem(PAGE_POS,false);
    

    【讨论】:

      【解决方案4】:

      我认为这是可能的。 1. 设置 ViewPager 的 item count 为 Integer.MAX_VALUE,当前 item 为 Integer.MAX_VALUE/2。它使您能够创建假无限滚动。 2.根据当前位置的片段实现您的逻辑。如果您将它们存储在适配器中,这很容易:

          @Override
          public Fragment getItem(int position) {
              ItemFragmentRoot fragment = new ItemFragmentRoot();
              mFragmentMap.put(position, fragment);
              return fragment;
          }
      
         @Override
          public void destroyItem(ViewGroup container, int position, Object object) {
              super.destroyItem(container, position, object);
              mFragmentMap.remove(position);
          }
      
          public ItemFragmentRoot getItem(int position){
              return mFragmentMap.get(position);
          }
      
      1. 我认为是最困难的部分。由于 ViewPager 每侧缓存至少 1 个视图,并且您不知道用户将采用哪种方式滚动,唯一的一种方法是根据滚动侧手动初始化和重新初始化出现的片段。在我之前提到的每个 ItemFragmentRoot 中使用嵌套片段。一切都取决于您的视图层次结构。

      如果你需要,我可以稍后再写代码。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-01-27
        • 1970-01-01
        • 1970-01-01
        • 2011-11-07
        • 1970-01-01
        相关资源
        最近更新 更多