Infinite Scrolling Image ViewPager
Asked Answered
B

7

15

As documented by Google, the Gallery class was deprecated in API level 16. This widget is no longer supported. Other horizontally scrolling widgets include HorizontalScrollView and ViewPager from the support library. So I used ViewPager as an alternative to the Gallery class.

My goal to finally achieve an infinite scrolling image ViewPager with text descriptions. I used the below code to achieve the image ViewPager with text describing each image but how do I apply Infinite Scrolling to a ViewPager?

I have not worked with ViewPager before so please try to provide detailed code if possible.

activity_main.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
       android:layout_width="fill_parent" 
       android:layout_height="fill_parent" 
       android:orientation="vertical">
  <android.support.v4.view.ViewPager 
       android:id="@+id/myimagepager" 
       android:layout_width="match_parent" 
       android:layout_height="match_parent" /> 
</LinearLayout>

custom_pager.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
   android:layout_width="match_parent" 
   android:layout_height="match_parent" 
   android:orientation="vertical"  
   android:gravity="center_horizontal">
   <ImageView 
       android:id="@+id/myimage" 
       android:layout_width="match_parent" 
       android:layout_height="0dp" 
       android:layout_margin="5dp" 
       android:layout_weight="2" /> 
    <TextView 
       android:id="@+id/image_text" 
       android:layout_width="fill_parent" 
       android:layout_height="0dp"   
       android:layout_weight="1"/>

</LinearLayout>

ImagePager:

public class ImagePager extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ImagePagerAdapter adapter = new ImagePagerAdapter(this, imageArra, stringArray );
        ViewPager myPager = (ViewPager) findViewById(R.id.myimagepager);
        myPager.setAdapter(adapter);
        myPager.setCurrentItem(0);
    }

    private int imageArra[] = { R.drawable.a, R.drawable.b,R.drawable.c, 
                                 R.drawable.d,R.drawable.e,R.drawable.f,
                                 R.drawable.g, R.drawable.h, R.drawable.i};

    private String[] stringArray = new String[] { "Image a", "Image b","Image c"
                                                   "Image d","Image e","Image f", 
                                                   "Image g","Image h","Image i"};


}

ImagePagerAdapter:

public class ImagePagerAdapter extends PagerAdapter {

    Activity activity;
    int imageArray[];
    String[] stringArray;

    public ImagePagerAdapter(Activity act, int[] imgArra, String[] stringArra) {
        imageArray = imgArra;
        activity = act;
        stringArray = stringArra;
    }

    public int getCount() {
        return imageArray.length;
    }

    public Object instantiateItem(View collection, int position) {
        LayoutInflater inflater = (LayoutInflater)collection.getContext
                          ().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View layout = inflater.inflate(R.layout.custom_pager, null);   

        ImageView im=(ImageView) layout.findViewById(R.id.myimage);             
        im.setImageResource(imageArray[position]);

        TextView txt=(TextView) layout.findViewById(R.id.image_text);
        txt.setText(stringArray[position]);

        ((ViewPager) collection).addView(layout, 0);
          return layout;   
    }

    @Override
    public void destroyItem(View arg0, int arg1, Object arg2) {
        ((ViewPager) arg0).removeView((View) arg2);
    }

    @Override
    public boolean isViewFromObject(View arg0, Object arg1) {
        return arg0 == ((View) arg1);
    }

    @Override
    public Parcelable saveState() {
        return null; 
    }


}
Boonie answered 2/12, 2012 at 10:54 Comment(2)
"gallery class deprecated .. after googled and searched alot , i end with ViewPager" Huh. It took me just a few seconds from typing 'gallery abdroid' (yes I did spell it wrong) into Google to end up at the docs for Gallery. The first 3 sentences state.. "This class was deprecated in API level 16. This widget is no longer supported. Other horizontally scrolling widgets include HorizontalScrollView and ViewPager from the support library." So a tip for future. Before anything else, read the docs. ;)Task
@Andrew Thompson my dear post updated , and i already saw that document from google , it was just to give reason why i shifted to viewpager , thanks.Boonie
J
32

I had the same problem, but I was able to find a way to solve it - the code can be found on github.

If you copy the classes InfiniteViewPager and InfinitePagerAdapter into your project, you can achieve infinite (wrapped) scrolling with some small changes.

In your Activity, wrap your PagerAdapter with an InfinitePagerAdapter:

PagerAdapter adapter = new InfinitePagerAdapter(new ImagePagerAdapter(this, imageArra, stringArray));

Change the ViewPager in the activity XML to be an InfiniteViewPager:

<com.antonyt.infiniteviewpager.InfiniteViewPager 
       android:id="@+id/myimagepager" 
       android:layout_width="match_parent" 
       android:layout_height="match_parent" />

You can rename the classes to whatever you want. This code only works if you have at least three pages (you have nine in your example code, so it will work fine for that).

Jampacked answered 9/12, 2012 at 12:57 Comment(6)
its work nicley but please i have question , now i have 4 classes in my project which is :1-ImagePager,2-ImagePagerAdapter,3-InfinitePagerAdapter,4-InfiniteViewPager.java. can we merge them in one class only or two class , this infinite image pager will be part of big project or we have to keep it as it consist of 4 class and does this will affect the performance or not , thanksBoonie
I don't think you will find any noticeable difference in performance from using 4 classes vs. 2 classes. It is better to keep them separate because then you can add the infinite scrolling behavior to any PagerAdapter/ViewPager you write later on - merging them all together will mean it cannot be easily reused in another context.Jampacked
OK i get it , another thing:1- why we dont have one adapter only in this project coz you mention :((wrap your PagerAdapter with an InfinitePagerAdapter)), why we did not write one adapter and called it:InfinitePagerAdapter, or there is specific behaviour must obtained by wrapping process , 2-you mention in your code :allow for 100 back cycles from the beginning, should be enough to create an illusion of infinity. that mean i have new 100 cycles each time i open my application would you please clarify this two points please , thanksBoonie
Your ImagePagerAdapter has a specific job - it serves up the layout for each page and doesn't have to worry about anything else. The InfinitePagerAdapter likewise only worries about infinite scrolling, not about the specific page being served - it does not load any views of its own. It is simply a design choice to separate them like this - one that allows the InfinitePagerAdapter to work with ANY PagerAdapter you write. The 100 cycles thing is for the lifetime of the View, which is generally the same as the lifetime of the Activity. Recreating the Activity will cause it to reset.Jampacked
Does it return correct correct selected position onClick of imageview?Sisak
How to add a page indicator?Rhizobium
K
9

I think my solution is simpler.

Attention to my array of images structure:

Item 0          => last image

Item count()-1  => first image

The trick is on onPageScrollStateChanged:

When user scrolls to last item -> the pager jumps without animation to first image (position = 1)

When user scrolls to first item -> the pager jumps without animation to last image (position = count - 2)

public class InfiniteScrollingActivity extends ActionBarActivity {

    private ViewPager     pager;
    private MyAdapter     adapter;
    int[] promoImageIds = new int[]{R.drawable.cover6, R.drawable.cover1, R.drawable.cover2, R.drawable.cover3, R.drawable.cover4, R.drawable.cover5, R.drawable.cover6, R.drawable.cover1 };

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

        adapter = new MyAdapter(getSupportFragmentManager(), promoImageIds);
        pager = (ViewPager)findViewById(R.id.pager);
        pager.setAdapter(adapter);
        pager.setCurrentItem( 1 );
        pager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageSelected(int index) {
                Log.v( "onPageSelected", String.valueOf( index ) );
            }

            @Override
            public void onPageScrolled(int arg0, float arg1, int arg2) {
                // Log.v("onPageScrolled", "");
            }

            @Override
            public void onPageScrollStateChanged(int state) {
                Log.v("onPageScrollStateChanged", String.valueOf(state));

                if (state ==ViewPager.SCROLL_STATE_IDLE) {
                    int index = pager.getCurrentItem();
                    if ( index == 0 )
                        pager.setCurrentItem( adapter.getCount() - 2, false );
                    else if ( index == adapter.getCount() - 1 )
                        pager.setCurrentItem( 1 , false);
                }
            }
        });
    }


    public static class MyAdapter extends FragmentPagerAdapter {

        int[] promoImageIds;

        public MyAdapter(FragmentManager fm, int[] promoImageIds){
            super(fm);
            this.promoImageIds = promoImageIds;
        }

        @Override
        public int getCount(){
            return promoImageIds.length;
        }

        @Override
        public Fragment getItem(int position) {

            return PromoFragment.newInstance( promoImageIds[position] );
        }
    }

    public static class PromoFragment extends Fragment
    {
        int imageID;


        static PromoFragment newInstance( int imageID)
        {
            PromoFragment f = new PromoFragment();

            // Supply num input as an argument.
            Bundle args = new Bundle();
            args.putInt( "imageID", imageID );
            f.setArguments(args);

            return f;
        }

        @Override
        public void onCreate(Bundle savedInstanceState)
        {
            super.onCreate(savedInstanceState);
            imageID = getArguments() != null ? getArguments().getInt( "imageID" ) : null;
        }

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState)
        {
            ImageView v = (ImageView) inflater.inflate(R.layout.fragment_image, container, false);
            v.setImageResource( imageID );
            return v;
        }
    }
}
Karafuto answered 2/9, 2014 at 17:54 Comment(3)
The tricky part was to read thoroughly your promoImageIds array, and be aware that you repeated the last and first elements in your array. Easy to implement and works like a charm!Boor
This approach worked the best for me, it doesn't suffer from the performance issues that the Int32.MaxValue Count approach does.Deeann
Works like a charm but the below indicator is not working properly int the list i have 3 data size its scroll infinite but the indicator show 2 can you solve thisSpiroid
L
6

i have already found a way by making simple trick , i hope it helps to you

import java.util.ArrayList;
import android.os.Bundle;
import android.app.Activity;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.util.Log;

public class ImagePager extends Activity {
    String[] stringArray;
    int[] imageArra;
    ViewPager myPager;
    Boolean isScrooled = false;
    // use this array yo understand swipe left or right ?
    ArrayList<Float> pos = new ArrayList<Float>();

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

            // put  empty view at the beginnig and to end

        imageArra = new int[] { 0, R.drawable.ic_launcher,
                R.drawable.ic_launcher, R.drawable.ic_launcher,
                R.drawable.ic_launcher, R.drawable.ic_launcher,
                R.drawable.ic_launcher, R.drawable.ic_launcher,
                R.drawable.ic_launcher, R.drawable.ic_launcher, 0 };

           // put  empty string at the beginnig and to end

        stringArray = new String[] { "", "Image a", "Image b", "Image c",
                "Image d", "Image e", "Image f", "Image g", "Image h",
                "Image i", "" };

        ImagePagerAdapter adapter = new ImagePagerAdapter(this, imageArra,
                stringArray);
        myPager = (ViewPager) findViewById(R.id.myimagepager);
        myPager.setAdapter(adapter);
        myPager.setCurrentItem(1);

        myPager.setOnPageChangeListener(new OnPageChangeListener() {

            @Override
            public void onPageSelected(int arg0) {
                Log.v("onPageSelected", String.valueOf(arg0));
                pos.clear();
            }

            @Override
            public void onPageScrolled(int arg0, float arg1, int arg2) {
                try {
                            // while scrolling i add ever pos to array
                    pos.add(arg1);
                                    // if pos.get(0) > pos.get(pos.size() - 1) 
                    // <----- swipe <-----  
                                    // we should check isScroll because setCurrent item is not a croll ? 

                    if (pos.size() > 0)
                        if (arg0 == imageArra.length - 1
                                & pos.get(0) > pos.get(pos.size() - 1)
                                & isScrooled == true) {
                            try {
                                isScrooled = false;
                                myPager.setCurrentItem(1, false);
                            } catch (Exception e) {
                                Log.v("hata",
                                        "<----- swipe <-----  " + e.toString());
                            }

                        }
                        // ----> swipe ---->
                        else if (arg0 == 0
                                & pos.get(0) < pos.get(pos.size() - 1)
                                & isScrooled == true) {
                            try {
                                isScrooled = false;
                                myPager.setCurrentItem(imageArra.length - 1,
                                        false);
                            } catch (Exception e) {
                                Log.v("hata",
                                        "----> swipe ---->  " + e.toString());
                            }

                        } else if (arg0 == 0 & pos.size() == 1
                                & isScrooled == true) {
                            try {
                                isScrooled = false;
                                myPager.setCurrentItem(imageArra.length - 1,
                                        false);
                            } catch (Exception e) {
                                Log.v("hata",
                                        "----> swipe ---->  " + e.toString());
                            }

                        }

                } catch (Exception e) {
                    Log.v("hata", e.toString());
                }

            }

            @Override
            public void onPageScrollStateChanged(int arg0) {
                Log.v("onPageScrollStateChanged", String.valueOf(arg0));
                            // set is scrolling
                isScrooled = true;
            }
        });

    }

}

[EDIT 1]

import java.util.ArrayList;
import android.app.Activity;
import android.os.Bundle;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.util.Log;

public class ImagePager extends Activity {
    String[] stringArray;
    int[] imageArra;
    ViewPager myPager;
    int scrollState;
    Boolean isFirstVisitEnd= true,isFirstVisitBegin = true;
    ArrayList<Integer> pos = new ArrayList<Integer>();


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

        imageArra = new int[] { 0,R.drawable.ic_launcher,
                R.drawable.ic_launcher, R.drawable.ic_launcher,
                R.drawable.ic_launcher, R.drawable.ic_launcher,
                R.drawable.ic_launcher, R.drawable.ic_launcher,
                R.drawable.ic_launcher, R.drawable.ic_launcher, 0 };

        stringArray = new String[] {"","Image a", "Image b", "Image c",
                "Image d", "Image e", "Image f", "Image g", "Image h",
                "Image i", "" };

        ImagePagerAdapter adapter = new ImagePagerAdapter(this, imageArra,
                stringArray);
        myPager = (ViewPager) findViewById(R.id.myimagepager);
        myPager.setAdapter(adapter);
        myPager.setCurrentItem(1);

        myPager.setOnPageChangeListener(new OnPageChangeListener() {
            @Override
            public void onPageSelected(int arg0) {
                Log.v("onPageSelected", String.valueOf(arg0));
                pos.clear();
                if (arg0 == imageArra.length - 1)
                    isFirstVisitEnd = false;
                else
                    isFirstVisitEnd = true;


                if (arg0 == 0)
                    isFirstVisitBegin = false;
                else
                    isFirstVisitBegin = true;
            }

            @Override
            public void onPageScrolled(int arg0, float arg1, int arg2) {                                
                try { 
                    pos.add(Integer.valueOf(arg2));

                    if (pos.size() > 0) {
                        //Log.v("onPageScrolled_arg2","arg0  : "+String.valueOf(arg0)+"   ilk : "+pos.get(0).toString()+"    son : " +pos.get(pos.size() - 1).toString()+ "   "+ String.valueOf(pos.get(0)-(pos.get(pos.size() - 1)))+"    isFirstVisitEnd: "+String.valueOf(isFirstVisitEnd.booleanValue()) );

                        // <----- swipe <-----
                        if (arg0 == imageArra.length - 2& (pos.get(pos.size() - 1) -pos.get(0)  < 100)& scrollState == 2 & isFirstVisitEnd == false) {                          
                            myPager.setCurrentItem(1, false);
                        }

                        //Log.v("onPageScrolled_arg2","arg0  : "+String.valueOf(arg0)+"   ilk : "+pos.get(0).toString()+"    son : " +pos.get(pos.size() - 1).toString()+ "   "+ String.valueOf(pos.get(0)-(pos.get(pos.size() - 1)))+"    isFirstVisitbegin: "+String.valueOf(isFirstVisitBegin.booleanValue()) );
                        if (arg0 == 0 & (pos.get(pos.size() - 1) -pos.get(0)  > -100)& scrollState == 2 & isFirstVisitBegin == false) {                         
                            myPager.setCurrentItem(imageArra.length - 2, false);
                        }       
                    }

                } catch (Exception e) {
                    Log.v("hata", e.toString());
                }

            }

            @Override
            public void onPageScrollStateChanged(int arg0) {
                Log.v("onPageScrollStateChanged", String.valueOf(arg0));
                scrollState =arg0;
            }
        });
    }
}
Luedtke answered 8/12, 2012 at 16:6 Comment(3)
ok its scroll continuously but still one thing the empty view still appear when reach to last view and want to continue to first one how we overcome this , thanksBoonie
Hi, it is hard to understand exact valu of pager position, but i changed the code and i think it is better now. Pls look at edit , and if you have some idea to improve its quality share with me([email protected]). I am plannig to develop infinite pager and put it to github.Luedtke
the first code is better than second but still both show the empty view . second one when scroll to reach empty view slowly it stack on it y have to scroll back one view then go forward agin to continue scrolling , thanksBoonie
D
6

I found another solution, based on Shlomi Hasin and antonyt answers, without modifying collection.

ViewPager yourPager;
PagerAdapter yourAdapter;
//....
EndlessPagerAdapter endlessPagerAdapter = new EndlessPagerAdapter(yourAdapter, yourPager);
yourPager.setAdapter(endlessPagerAdapter);
yourPager.setCurrentItem(1);//for correct first page

Full class:

public class EndlessPagerAdapter extends PagerAdapter {

private PagerAdapter adapter;

public EndlessPagerAdapter(PagerAdapter adapter, ViewPager viewPager) {
    this.adapter = adapter;
    viewPager.addOnPageChangeListener(new SwapPageListener(viewPager));
}

@Override
public int getCount() {
    return adapter.getCount() + 2;
}

@Override
public Object instantiateItem(ViewGroup container, int position) {
    if (adapter.getCount() < 2) {
        adapter.instantiateItem(container, position);
    }

    int newPosition;
    if (position == 0) {
        newPosition = adapter.getCount() - 1;
    } else if (position >= getCount() - 1) {
        newPosition = 0;
    } else {
        newPosition = position - 1;
    }
    return adapter.instantiateItem(container, newPosition);
}

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

@Override
public void finishUpdate(ViewGroup container) {
    adapter.finishUpdate(container);
}

@Override
public boolean isViewFromObject(View view, Object object) {
    return adapter.isViewFromObject(view, object);
}

@Override
public void restoreState(Parcelable bundle, ClassLoader classLoader) {
    adapter.restoreState(bundle, classLoader);
}

@Override
public Parcelable saveState() {
    return adapter.saveState();
}

@Override
public void startUpdate(ViewGroup container) {
    adapter.startUpdate(container);
}

@Override
public CharSequence getPageTitle(int position) {
    return adapter.getPageTitle(position);
}

@Override
public float getPageWidth(int position) {
    return adapter.getPageWidth(position);
}

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

@Override
public void unregisterDataSetObserver(DataSetObserver observer) {
    adapter.unregisterDataSetObserver(observer);
}

@Override
public void registerDataSetObserver(DataSetObserver observer) {
    adapter.registerDataSetObserver(observer);
}

@Override
public void notifyDataSetChanged() {
    adapter.notifyDataSetChanged();
}

@Override
public int getItemPosition(Object object) {
    return adapter.getItemPosition(object);
}

private class SwapPageListener implements ViewPager.OnPageChangeListener {

    private ViewPager viewPager;

    SwapPageListener(ViewPager viewPager) {
        this.viewPager = viewPager;
    }

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

    }

    @Override
    public void onPageSelected(int position) {

    }

    @Override
    public void onPageScrollStateChanged(int state) {
        if (state == ViewPager.SCROLL_STATE_IDLE) {
            PagerAdapter pagerAdapter = viewPager.getAdapter();
            if (pagerAdapter != null) {
                int itemCount = pagerAdapter.getCount();
                if (itemCount < 2) {
                    return;
                }
                int index = viewPager.getCurrentItem();
                if (index == 0 ) {
                    viewPager.setCurrentItem(itemCount - 2, false);
                } else if (index == itemCount - 1) {
                    viewPager.setCurrentItem(1, false);
                }
            }
        }
    }
}}

How it works:

We have some collection

collection

then add two additional items to it

new size

show first element on last position and last element on first position

show elements

add listener and swap pages on event, from 4 to 1 and from 0 to 3

swap elements

thats all.

I would not advise you to apply animation there or heavy layouts, it can be lagging when elements swap.(maybe, I did not encounter any lags)

Also don't set this adapter to pager more than once, or move SwapPageListener to external class and set it in initialization block.

Dioptase answered 16/10, 2017 at 14:9 Comment(0)
P
0

For infinite scrolling with days it's important you have the good fragment in the pager therefore I wrote my answer on this on page (Viewpager in Android to switch between days endlessly)

It's working very well! Above answers did not work for me as I wanted it to work.

Petta answered 1/5, 2014 at 15:35 Comment(0)
P
0

RecyclerViewPager has implement infinite scrolling and can scroll like a gallery.

Peso answered 30/10, 2015 at 2:32 Comment(0)
H
0
if ((pagerBottom.getCurrentItem() + 1) == (sliderimageDetails.size())) {
    pagerBottom.setCurrentItem(0);
} else {
    pagerBottom.setCurrentItem((pagerBottom.getCurrentItem() + 1));
}
Hypoblast answered 20/7, 2018 at 12:35 Comment(1)
Explain and indent your answer!Reconcile

© 2022 - 2024 — McMap. All rights reserved.