A ViewPager and a PagerAdapter that can:
- AutoScroll (On/Off able)
- Infinite Loop (On/Off able)
- ViewPager's height can be wrap_content
- Adjustable auto scroll interval
- Won't scroll nor loop if there is only 1 item
- Works well with notifyDataSetChanged()
- Supports page indicators
Although there are already quite a number of similar libraries out there,
I cannot find one that fits all of the below requirements:
- Sufficient documentation
- Last updated in less than 3 years
- Good infinite looping effect
- Configurable auto-scroll
- ViewPager that supports wrap_content (or at least aspect ratio)
- Good support with Page Indicators
Especially for 6, even some of them supports, they provide built-in indicators only; or does not tell user how to implement their own indicator.
I wrote this library to tackle all of these problems I faced after trying a whole day with other libraries.
First make sure jcenter()
is included as a repository in your project's build.gradle:
allprojects {
repositories {
jcenter()
}
}
And then add the below to your app's build.gradle:
implementation 'com.asksira.android:loopingviewpager:1.0.0'
<com.asksira.loopingviewpager.LoopingViewPager
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:isInfinite="true"
app:autoScroll="true"
app:scrollInterval="2000"
app:wrap_content="true"/>
Attribute Name | Default | Allowed Values |
---|---|---|
isInfinite | false | true / false |
autoScroll | false | true / false |
wrap_content | true | true / false |
scrollInterval | 5000 | any integer (represents ms) |
If you wonder why you need to set app:wrap_content="true"
, take a look at this Stackoverflow post.
You should
- Specify the data type in the generic (
<DataType>
) - Create your own constructor according to this
DataType
- override
getItemView
public class DemoInfiniteAdapter extends LoopingPagerAdapter<Integer> {
public DemoInfiniteAdapter(Context context, ArrayList<Integer> itemList, boolean isInfinite) {
super(context, itemList, isInfinite);
}
//You should return the View (With data binded) to display in this method.
@Override
protected View getItemView(View convertView, int listPosition, ViewPager container) {
if (convertView == null) {
convertView = LayoutInflater.from(context).inflate(R.layout.item_pager, null);
container.addView(convertView);
}
//Bind your view elements with data in itemList here.
//You can also consider using a ViewHolder pattern.
//Below is just an example in the demo app.
convertView.findViewById(R.id.image).setBackgroundColor(context.getResources().getColor(getBackgroundColor(listPosition)));
TextView description = convertView.findViewById(R.id.description);
description.setText(String.valueOf(itemList.get(listPosition)));
return convertView;
}
}
adapter = new DemoInfiniteAdapter(context, dataItems, true);
viewPager.setAdapter(adapter);
@Override
protected void onResume() {
super.onResume();
viewPager.resumeAutoScroll();
}
@Override
protected void onPause() {
viewPager.pauseAutoScroll();
super.onPause();
}
If you have new data to update to your adapter, simply call:
adapter.setItemList(newItemList);
viewPager.reset(); //In order to reset the current page position
I don't provide a built-in page indicator because:
- ViewPager and Indicator are logically separated
- I want to make this library adaptable to all page indicators
With that said, I personally suggest using this PageIndicatorView.
I create this demo and tested using this library.
There are 2 callbacks in LoopingViewPager
that are designed to tell a PageIndicator 2 things:
- I am now being scrolled to a new page, please update your indicator transition position;
- I am now being selected to a new page, please update your indicator selected position.
And a public method getIndicatorCount()
that can tell the indicator how many indicators(dots) should it show.
And here is an example using PageIndicatorView:
//Do not bind IndicatorView directly with ViewPager.
//Below is how we achieve the effect by binding manually.
//Tell the IndicatorView that how many indicators should it display:
indicatorView.setCount(viewPager.getIndicatorCount());
//Set IndicatorPageChangeListener on LoopingViewPager.
//When the methods are called, update the Indicator accordingly.
viewPager.setIndicatorPageChangeListener(new LoopingViewPager.IndicatorPageChangeListener() {
@Override
public void onIndicatorProgress(int selectingPosition, float progress) {
indicatorView.setProgress(selectingPosition, progress);
}
@Override
public void onIndicatorPageChange(int newIndicatorPosition) {
indicatorView.setSelection(newIndicatorPosition);
}
});
Don't forget to update the indicator counts if you updated items in adapter:
indicatorView.setCount(viewPager.getIndicatorCount());
By implementing this way, you can basically use any indicators you like, as long as that indicator allows you to configure programmatically (1) The number of indicators; (2) Which indicator is selected. And even, if it supports, (3) The progress of indicator transition effect.
P.S. However, due to this bug of PageIndicatorView, the transition effect on indicators cannot be shown until the author release his fix in development branch.
Copyright 2017 Sira Lam
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the LoopingViewPager), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.