Home » Android » java – Sliding between fragments

java – Sliding between fragments

Posted by: admin June 15, 2020 Leave a comment

Questions:

I’m developing an app and currently I am trying to add ScreenSlide to it. I managed to do this using a tutorial, but usual sliding between x pages is not quite what I’m looking for.

With code provided below I can slide between 5 pages, but pages aligned in a straight line and you can’t go from first page straight to 5th and vise versa.
In my app I have 4 pages. When I slide left I switch between first 2 pages, when I slide right I switch between 2 last pages. On image below you can see how my current code switches page and under it – my goal.

enter image description here

    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]; 
        }

    }


}

[UPDATE]

I’ve managed to write a code that allows me to infinitely slide to the right between 6 different pages. Left side is limited though – I can slide only to the first page(so if I’m on 1st page after I cycled 3 times to the right, I can make only 3 cycles backwards). I think I am very close to finding the solution. Any ideas?

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;
        }
        }
How to&Answers:

One possible workaround is not using viewpager, but creating your own custom Slider, I ended up with this solution, since ViewPager is very unflexible, like for example if you try to do something like Facebook Page app kind of thing.
Cons: you have to manage all the touches and lifecycle.

Another simpler solution for this is basically use the following API if I understand the question correctly it should be enough.
ViewPager.setCurrentItem

Answer:

This is what I would do.

Since you have a finite amount of screens, I would make an array to save each instance of the ScreenSlidePageFragment you make under a corresponding index. So you can get an instance from that array by using “position”. This will allow you to leverage getItem function to do something like

...
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]; 
}

Note: code not tested

Basically, you will need to write out the logic to return an existing instance of a fragment based on where you are currently and which position is requested.

Answer:

You can try ViewPager.setCurrentItem

If you want to navigate to page

viewPager.setCurrentItem(PAGE_POS);

If you want to navigate to page without smooth scroll

viewPager.setCurrentItem(PAGE_POS,false);

Answer:

I think it’s possible to do.
1. Set ViewPager’s item count to Integer.MAX_VALUE and current item to Integer.MAX_VALUE/2. It gives you ability to create fake infinite scroll.
2. Realize your logic depending on fragment on current position. It is easy if you store them in your adapter:

    @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. And the most difficult part, I think. Since ViewPager cache at least 1 view each side and you don’t know which way user going to scroll the only one way is to manualy initialize and reinitialize appearing fragment according to scroll side. Use nested fragment inside each ItemFragmentRoot I mentioned before. All depends on how heavy your view hierarchy.

I can write more code later, if you need.